I have written many messages already. I think, the purpose of this operator
is clear.
In this discussion I have come up to understanding what I would like to use.
You suggest very hard and complex solutions:
<?*js*html= $str ?>
<?php['html']: ?>
$escape = new SplEscaper; $escape->support('e', function () { ... });
declare('filter=htmlentities');
This is not what I wanted to suggest.
I have rewritten RFC a little. There is no tricks with ZEND_NAME_NOT_FQ,
there is no magic constants, there is no problems with autoloading. The
soultion is small, simple, and customizable.
https://wiki.php.net/rfc/escaping_operator
There are 3 functions:
callable|null set_escape_handler(callable $handler)
bool restore_escape_handler()
escape_handler_call(mixed $string, mixed $context)
They work similar to set_error_handler() / restore_error_handler().
Operator is compiled into the following AST:
echo escape_handler_call(first_argument, second_argument);
Function escape_handler_call() just pass given arguments into user-defined
handler. Second argument is not required. If the handler is not set, it
throws an exception. There is no default handler for any context, to
prevent 'built-in' wrong work of <?* $str ?> constructions in non-HTML
contexts like CSV. This is not hard to create a handler once. Default
context can be set in it as default value for second argument.
set_escape_handler(function($str, $context = 'html') {
...
});
What is under discussion:
Starting sign.
Last one is more comfortable to type.
<?* $a, $b ?>
<?: $a, $b ?>
Separator sign.
Maybe it should differ from standard <?= $a, $b ?> syntax to prevent
mistakes like <?= $a, 'html' ?> instead of <?* $a, 'html' ?>. '|' won't
give error, but looks more similar to escaping in template engines.
<?* $a , $b ?>
<?* $a | $b ?>
<?* $a |> $b ?>
<?: $a : $b ?>
If to wrap functions in a class or namespace (fully qualified), to not
clutter up a global namespace:
set_escape_handler()
restore_escape_handler()
escape_handler_call()
PHPEscaper::setEscapeHandler()
PHPEscaper::restoreEscapeHandler()
PHPEscaper::escapeHandlerCall()
And also any names in source code or details of implementation, without
changing main algorithm.
What is not under discussion:
Built-in contexts.
Because escape_handler_call() is not an escaper itself, but just a helper
to call user-defined escaper, it should not handle any contexts. This
allows to prevent 'built-in' wrong work of <?* $str ?> constructions in
non-HTML contexts like CSV.
Multiple arguments.
<?* $a, 'js', 'html' ?>
I think, it is enough that second argument can be of any type, e.g. an
array.
Complicated syntax like <?*html*js= $str ?>.
If we allow custom handlers, then we need runtime processing, so the
example above cannot be compiled into
<?= htmlspecialchars(json_encode($str)) ?>
directly, and it will something like
<?= escape_handler_call(escape_handler_call($str, 'html'), 'js') ?>
I.e. we anyway need to pass context as a second argument, so why not allow
user to do it.
If someone wants more complex solution or built-in template engine, he can
create another RFC and suggest his own implementation.