php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #75179 Remove undocumented assignment operator precedence change
Submitted: 2017-09-10 11:44 UTC Modified: 2017-09-11 00:03 UTC
Votes:2
Avg. Score:4.5 ± 0.5
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:1 (50.0%)
From: codedokode at gmail dot com Assigned:
Status: Suspended Package: Scripting Engine problem
PHP Version: Irrelevant OS: Windows XP
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2017-09-10 11:44 UTC] 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

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-09-10 14:28 UTC] 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 14:44 UTC] cmb@php.net
-Status: Open +Status: Suspended
 [2017-09-10 14:44 UTC] 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-11 00:03 UTC] nikic@php.net
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.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue May 07 19:01:29 2024 UTC