On 22/07/2016 08:31, Michael Vostrikov wrote:
>> sticking the escaping types after the output makes it hard to spot what's
> going on with anything other than a simple variable. e.g. <?*
> $this->renderView($thing->getViewName(), 'html'), 'js' ?>
>
> In Twig escapers and filters are also written after a variable, and this is
> not confusing for many users.
> {{ render(thing.viewName, 'html') | escape('js') | somefilter }}
Sure, but in Twig, Smarty, etc filters aren't just a special syntax for
doing escaping, they're a fundamental part of the language. In essence,
they're just a different way of writing a function call, a bit like
Sara's pipe operator, which incidentally would allow this:
<?= render($thing->viewName, 'html') |> escape($$, 'js') |>
somefilter($$) ?>
>> Because it's not obviously part of the <?* operator, someone might think
> the escape parameter can be used elsewhere: <?php echo
> '<blink>oops</blink>', 'html' ?> Operators don't normally have a list of
> arguments.
>
> Just a default variable, nothing complicated.
> If they write echo like this, they will notice 'oopshtml' and then correct
> this contstruction.
> Binary operators have 2 arguments (add($a, $b), escape($string, $context)),
> 'for' has 3 arguments.
Binary operators have a left-hand operand and a right-hand operand;
unary operators have an operand immediately before or immediately after
their symbol. You don't write +$a, $b you write $a + $b. The only
exception is the ternary decision operator, $a ? $b : $c, which still
doesn't use a comma.
Functions, on the other hand, have a name, and a pair of brackets. So
+($a, $b) looks a bit like a function call with a funky name; that would
give us <?*( $foo, 'html') ?>.
I can see your logic in defining it this way, it just doesn't look like
anything else in the language, and that's a bad thing for people using
it properly.
>> And this is the reason why I want it to be a call of function with constant
>> name. This is very clear - <?* $str, $context ?> turns into
>> some_escape_function($str, $context).
The more you compare it to a function call, the less I understand how it
gains over just defining a function e() and writing <?= e( $foo, 'html') ?>
>> What happens if you mistype the argument? <?* $foo, 'hmtl' ?> Or with the
> current proposal's use of '|', what if you get that syntax wrong? <?* $foo,
> 'html || js' *?> <?* $foo, 'html, js' ?>
>
> Exception: Unknown context 'hmtl'.
> Exception: Unknown context ''.
> Exception: Unknown context 'html, js'.
>
> If the handlers for these contexts are not set, of course.
But if these are run-time errors, how is the clever syntax helping
people get it right here? If you can pass a variable as the escaping
method, define arbitrary escaping functions, etc, you can't even write a
strict static analyser.
>> if you're mentioning the whole function name, you can just call it already
>> <?*html= $foo ?>
> Do you mean the function autoloading? What is the difference with not-fq
> name 'PHPEscaper' then?) And how to use an escaper like [$this, 'html'] ?
You've merged two unrelated lines from my e-mail here, so I'm not sure
what your question is. By the first line, I meant that if you write
"<?[$this, 'html'] $foo ?>" you might as well just write "<?=
$this->html($foo) ?>". The syntax has gained you nothing but a minimum
version of PHP and some head-scratching from new users.
>> JS escape only; not sure if this should encode as JSON, or just a JS safe
> string; maybe <?*json= $foo ?> as well / instead...
> This looks unclear for me - why I cannot use json for strings and what if
> my variable sometimes is an array, sometimes a string?
'foo' is valid JSON - there is much hot air about the difference between
a "JSON value", a "JSON document", etc, but long story short, it is
perfectly fine to say <?= json_encode('hello world') ?>
On the other hand, if I have an array and ask for it to be HTML-escaped,
nothing iterates the array for me, it will just print "Array". So if I
ask for it to be "JS-escaped", why should it magically produce a JSON
array? Not to mention the fact that PHP "arrays" cannot be losslessly
represented as either an object or an array in JS (they have both
arbitrary keys and well-defined order, JS makes you choose one or the
other).
>> The biggest use case for this is people who *aren't* using a framework
> ... so customising the definitions is going to be the exception, not the
> rule
> They can setup their escapers once, this is not a problem, but the problem
> is e.g. default flags for html escaping.
> Customization is required.
Customizability is required, yes, but it absolutely should not be
mandatory. If people are using a framework already, *they will already
have a method of doing this*. This feature is really only useful for
people who are relying on absolutely minimum framework code, who want
something to work "out of the box".
If I have to write "register_escape_handler(function($string,
$mode='html') { .... })" I might as well just write "function e($string,
$mode='html') { .... }". There's not even a question of autoloading,
because nothing is going to autoload the procedural code that runs
"register_escape_handler" anyway.
>> If we make it too flexible, we're basically inventing a new templating
> language
> We cannot forbid a customization, so any custom escaper is a kind of new
> templating language.
> The operator must be simple for use. If someone wants to create new
> templating language in his application, let he create. It will be in
> application, not in PHP.
I think we're in agreement here - simplicity is key. :)
>> The trick with the magic class name and namespace aliasing is neat, but
> feels likely to confuse a lot of users
>
> Yes, I have to agree. Maybe more better way is to make it similar to
> set_error_handler() - not for context as it is in RFC, but for 'escape'
> callable.
Personally, I think having a separate handler registered for each
context argument, like streams, makes more sense. I don't see the use
case for customising how contexts are combined, passing variable
contexts around, or anything else that is gained by one callback with
two parameters.
Again, focusing on simplicity:
<?php
set_escape_handler('html', 'htmlspecialchars');
set_escape_handler('json', 'json_encode');
?>
<?*html*json= $foo ?>
becomes:
<?php echo htmlspecialchars(json_encode($foo)); ?>
And, as I say, the common escape handlers should be defined by default,
just like a whole bunch of stream types are.
Regards,
--
Rowan Collins
[IMSoP]