PHP Operator precedence

If you take a look in the PHP-manual regarding operator precedence you will find the following quote:


Although
! has a higher precedence than =, PHP will still allow expressions similar to the following: if (!$a = foo()), in which case the return value of foo() is put into $a.


This is not very informative, which expressions are similar to this expression?

The answer to this can be found in this (huge!) file. This file is made with a tool called 'generate-prec-rules', which was created this week. It does exactly what the name implies, it generates the precedence rules given a set of common-precedence rules. The file above is created with the precedence rules from the yacc-definition of PHP version 5.

But how can we interpret these rules? Let's take a look at an example rule:

context-free priorities
"@" Expr -> Expr
<1> >
Expr "/" Expr -> Expr

This rule disallows a "/" on the second position of the '@'. Please note that this notation also counts the string-literal.

However, the expression @ 4 / 5 is not invalid, it can still be parsed and evaluated. The rule above just explains how PHP places the parenthesizes in the expression, in this case like this:
  (@ 4 ) / 5.
Take a minute to think about the expression and how it is influenced by the above rule, it took me a while to figure it out.

It is nice to have all of the rules, they describe the operator precedence very precisely, but the size of the file is a bit problematic. Every operator, there are about 32, gets a rule for each other operator for each expression it has. The '*' alone already occurs in 82 rules.

So the next step that we will have to take is to combine rules without changing the semantics of the precedence relations. An example of this is the combination of these two rules:

context-free priorities
Expr "*" Expr -> Expr
<2> >
Expr "+" Expr -> Expr

context-free priorities
Expr "*" Expr -> Expr
<0> >
Expr "+" Expr -> Expr

into this rule:

Expr "*" Expr -> Expr
> Expr "+" Expr -> Expr

Which means the same, but is a bit more compact and probably more understandable.

So when this tool is created, and some things are changed within SDF, we can incorporate the newly generated precedence rules into PHP-Front. This will solve some parsing problems and will give us an even better SDF-grammar for PHP. We will also try to generate a more understandable, one page list of the operator precedence within PHP to replace the quote in the current PHP-documentation.

A nice example of 'research meets real life' don't you think?

3 comments:

Martin said...

Nice introduction to what we are trying to achieve :)

Anonymous said...

Hi Eric, I stumbled upon your post when I was searching more information on PHP's operator precedence. There is just no information how the -> (object dereference) and ${} (variable name dereference) operators are handled.

Most importantly, I want to know, if there is a one-statement statement to call a function stored in an object property, like this:
class test { var $x; }
and within test, do: ($this->x)()

As reference, I also read:
https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y

Shouldn't it work in the latest version of PHP because callable_expr includes '(' expr ')' ?

It did not work in PHP v5.6.2 however. Do you have an idea?

Best, Adrian

Eric Bouwers said...

Hi Adrian,

It seems that what you want to achieve can be done with:

$this->{$this->x}();

Check out the callable_variable definition, which can call a member_name, which can be an expr within curly braces.

Hope this helps!