Req #75179 [Sus]: Remove undocumented assignment operator precedence change

From: Date: Mon, 11 Sep 2017 00:03:59 +0000
Subject: Req #75179 [Sus]: Remove undocumented assignment operator precedence change
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-211047@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=75179&edit=1

 ID:                 75179
 Updated by:         nikic@php.net
 Reported by:        codedokode at gmail dot com
 Summary:            Remove undocumented assignment operator precedence
                     change
 Status:             Suspended
 Type:               Feature/Change Request
 Package:            Scripting Engine problem
 Operating System:   Windows XP
 PHP Version:        Irrelevant
 Block user comment: N
 Private report:     N

 New Comment:

This is documented in the language spec, see for example https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#simple-assignment.
The assignment accepts a "variable" as the LHS, not an arbitrary (or
precedence-constrained arbitrary) expression.

In any case, I doubt this is going to change. While there are a few cases where this results in
unexpected behavior (the ones I've seen where it resulted in some genuine confusion were
combinations of &= and non-reference expressions), usually it means that things tend to just
work. The fact that !$a = foo() and similar do not require parenthesis is intentional.

Of course, it may be that this requires additional documentation. There are no particular special
rules involved here, just that the LHS of assignments (and other similar expressions such as
increments and decrements) must be variable expressions and precedence only comes into play once
this constraint has been satisfied. 

ther implementations and static analyzers don't have a problem dealing with this, as long as
they have a correct parser implementation.


Previous Comments:
------------------------------------------------------------------------
[2017-09-10 14:44:19] cmb@php.net

Thank you for your interest in PHP and for submitting a feature
request. Please be aware that due to the magnitude of change this
request requires, it would be necessary to discuss it on PHP
Internals list (internals@lists.php.net) as an RFC. Please read
the guide about creating RFCs here:
<https://wiki.php.net/rfc/howto>. If you
haven't had experience
with writing RFCs before, it is advised to seek guidance on the
Internals list (<http://php.net/mailing-lists.php>) and/or solicit
help from one of the experienced developers. 

Please do not consider this comment as a negative view on the
merits of your proposal – every proposal which requires changes of
certain magnitude, even the very successful and widely supported
ones, must be done through the RFC process. This helps make the
process predictable, transparent and accessible to all developers.

------------------------------------------------------------------------
[2017-09-10 14:28:07] cmb@php.net

> I also checked PHP language spec by Facebook [3] and didn't
> found there anything about this feature. I understand that is a
> third-party specification but there seems to be no any other
> specifications.

No, this is actually the PHP language specification to which the
php.net PHP implementation is supposed to conform.

------------------------------------------------------------------------
[2017-09-10 11:44:21] codedokode at gmail dot com

Description:
------------
Accidently I found out that PHP allows ambiguous expressions like this: 

$a + $b = 1;

Documentation states that plus operator has higher precedence than assignment operator (which is the
case for similar expression $a = 1 + 2), therefore I expected the code to produce a syntax error,
but there were only warnings about undefined variables [1]

I googled around and found out that there are some undocumented hacks in the parser that make it
ignore operator precedence in assignment. They are not documented, the documentation [2] only
mentions that "Although = has a lower precedence than most other operators, PHP will still
allow expressions similar to the following: if (!$a = foo()), in which case the return value of
foo() is put into $a.". There is no clear description, what types of invalid expressions are
allowed, and how they are interpreted.

I also checked PHP language spec by Facebook [3] and didn't found there anything about this
feature. I understand that is a third-party specification but there seems to be no any other
specifications.

I found several bugs where a similar question was asked: bug #17386, bug #63825, bug #40820. It
looks like PHP tries to "guess" author's intent and "fix" the code. In all
those bugs PHP developers confirmed that this behaviour was intended. 

As it turned out, PHP can also change precedence even in expressions without assignment operator:
bug #73802

I think this is wrong because: 

- the rules for changing precedence are not documented, it is unclear what result the code will
produce. 
- there are alternative PHP implementations (like HHVM) that will probably not support this
transformation, therefore the same code might work differently in different PHP implementations.
- PHP is unable to guess author's original intent and producing a clear syntax error message
will help author to find the reason of error faster rather than pretending that the code is correct
and confusing the author
- when static analysis tools find expression like $a + $b = 1, they cannot state that this is a
mistake because this code in fact works

For example, I saw a code where the author thought that assignment target is written on the right
and wrote a line like $a + $b = $c. PHP interpreted the expression as ($a + ($b = $c)) but the
original intent was $c = $a + $b. We see that the "fix" by PHP parser only have confused
the author and a syntax error message would be much more useful in this case.

The use cases where this behaviour might be useful like if (!$a = fn()), are rare.

My suggestions are: 

- admit that the parser is unable to guess author's original intent and this behaviour is
undesirable in future versions of PHP
- add a warning or deprecation notice when precedence is changed by the parser with clear
description of the problem
- remove precedence changing in some future PHP version and produce syntax errors

If we don't start producing warnings, authors will continue to write such code and even many
years later PHP developers (and maybe developers of alternative implementations) will have to
support this undocumented feature.

If necessary, I could try to make the pull request myself, but later when I have time for this. 

This bug can be assigned a low priority.

[1] https://3v4l.org/ATpvW
[2] http://php.net/manual/en/language.operators.precedence.php
[3] https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#assignment-operators


Test script:
---------------
<?php 
// https://3v4l.org/ATpvW
$a + $b = 1;


Expected result:
----------------
Syntax error 

Actual result:
--------------
No syntax error


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=75179&edit=1


Thread (4 messages)

« previous php.bugs (#211047) next »