Hello all!  Longtime PHP user, first-time contributor to internals (sorry
if I screw anything up)!

I'd like to propose either the deprecation (7.next - likely 7.4 at this
point) and removal (8.0) of the T_LOGICAL_OR (or), T_LOGICAL_AND (and), and
T_LOGICAL_XOR (xor) tokens, or aliasing them to ||, &&, and != respectively.

The behaviours of the two sets of logical operators are very similar (it's
incredibly unclear how $x or $y would differ from $x||$y).  They perform
almost identically except for the fact that the former set has a precedence
lower that the assignment, null coalescing, and ternary operators[1].  The
page on logical operators[2] states that the reason the two variations
exist is that they "operate at different precedences" (which isn't a reason
for existence, but rather a statement of differences).

Example #1 on the logical operators page[2] gives an example of this
difference:
$e = false || true; // true
$f = false or true; // false

Because of the difference of precedence, the second line is evaluated as
($f = false) or true;

In my mind (and in the mind of every programmer I've spoken to about this),
this violates the principle of least astonishment[3].  The assignment
operator is usually thought to be the lowest level of precedence other than
parenthesis (as a typical statement would be "do some thing, then assign
its value to this varible").

This[4] stackoverflow question sheds some light on the intent of the
alternative operators - they are used for "control flow" in the style of
Ruby's "unless" operator[5]:

defined("SOME_CONSTANT") or die("SOME_CONSTANT was not defined");

However, this behaviour has nothing to do with the difference of precedence
- rather this is due to short circuiting.

The only difference between the two (unless there are interactions I'm not
aware of with the ternary or null coalescing operator) is the precedence
with the assignment operator, causing the return value to be assigned
without respect to the conditional.  I ran a quick (possibly imperfect)
script on GitHub's top 30 repositories, and of the usages of the
T_LOGICAL_* operators all but this one[6] operated equivalently to the
symbolic ones:
$gdImage = @imagecreatetruecolor(120, 20) or die('Cannot Initialize new GD
image stream');

In this case, the result of imagecreatetruecolor is intended to be placed
in $gdImage, or if it is falsey, die with an error.  This could be
rewritten as:
($gdImage = @imagecreatetruecolor(120, 20)) || die('Cannot Initialize new
GD image stream');

Or, in my opinion, more cleanly:
$gdImage = @imagecreatetruecolor(120, 20);
if(!$gdImage) die('Cannot Initialize new GD image stream');

I've written a very rough draft RFC here[7] - and I would love feedback.
If it's taken well I can put it up on the wiki.

Thanks,
Ryan "Iggy" Volz

[1]: http://php.net/manual/en/language.operators.precedence.php
[2]: http://php.net/manual/en/language.operators.logical.php
[3]: https://en.wikipedia.org/wiki/Principle_of_least_astonishment
[4]: https://stackoverflow.com/a/5998351
[5]:
https://www.tutorialspoint.com/ruby/ruby_if_else.htm#Ruby%20unless%20modifier
[6]:
https://github.com/PHPOffice/PhpSpreadsheet/blob/aa5b0d0236c907fd8dba0883f3ceb97cc52e46ec/samples/Basic/25_In_memory_image.php#L24
- likely copied from
http://php.net/manual/en/function.imagecreatetruecolor.php
[7]: https://github.com/iggyvolz/Unifying-Operators-RFC

Reply via email to