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.

Reply via email to