Orden de evaluación en PHP

Nota del traductor. Nikita Popov ha hecho y sigue contribuyendo enormemente al desarrollo del lenguaje PHP. Entiende muy bien las partes internas del motor PHP y en este artículo explica algunas de las características de PHP en términos del orden de evaluación de expresiones, que, quizás, no se puede encontrar en ningún otro lugar. Este artículo tiene alrededor de 7 años y prácticamente no ha perdido su relevancia, sin embargo, es bastante difícil encontrarlo, porque no está en el blog de Nikita Popov, sino que está publicado en sus gist-s en github. Creo que será útil presentarlo a la comunidad en ruso.



En mi comunidad de reddit favorita, lolphp , encontré una publicación en la que la gente se sorprende con el resultado del siguiente código:



<?php

$a = 1;
$c = $a + $a++;
var_dump($c); // int(3)

$a = 1;
$c = $a + $a + $a++;
var_dump($c); // int(3)


Como puede ver, las expresiones ($a + $a++)y ($a + $a + $a++)dan el mismo resultado, lo cual es bastante inesperado. ¿Que está pasando aqui?



Precedencia y asociatividad de operadores



Mucha gente piensa que el orden en el que se evalúa una expresión está determinado por la precedencia y la asociatividad de los operadores , pero este no es el caso. La prioridad y la asociatividad determinan solo el orden en el que las operaciones se agrupan en una expresión.

En la primera expresión, $c = $a + $a++;el incremento posterior "++" tiene prioridad sobre "+", por lo que $ a ++ es un grupo separado:



$c = $a + ($a++);


$c = $a + $a + $a++; - "++" , "+":



$c = $a + $a + ($a++);


"+" - , "+" :



$c = ($a + $a) + ($a++);


: , .



? . , , . , , ($a + $a), ($a++) .



PHP . PHP , — . , - .



CV



-, , PHP , , ( PHP).



(compiled variables, CV), PHP 5.1. (, $a, $a->b $a['b']) . — , PHP , Zend VM ( Zend). 2 .



, .

$a + $a + $a++:



// code:
$a = 1;
$c = ($a + $a) + ($a++);


// opcodes:
         ASSIGN   $a, 1
$tmp_1 = ADD      $a, $a
$tmp_2 = POST_INC $a
$tmp_3 = ADD      $tmp_1, $tmp_2
         ASSIGN   $c, $tmp_3


:



  • $a = 1,
  • $a + $a $tmp_1,
  • - $a $tmp_2,
  • , , $c.


( $a + $a, $a++), , , .



$a + $a++:



// code:
$a = 1;
$c = $a + ($a++);


// opcodes:
         ASSIGN   $a, 1
$tmp_1 = POST_INC $a
$tmp_2 = ADD      $a, $tmp_1
         ASSIGN   $c, $tmp_2


, POST_INC ($a++) , $a ADD. ? . . CV .



CV



: , CV - @. PHP 5.x, PHP 7 . , PHP 5 , , - - CV CV.



PHP 5.x

() , CV , , @.



. $a + $a++, , @:



<?php

$a = 1;
@ $c = $a + $a++;
var_dump($c); // int(2)


, , 3 2. , :



         ASSIGN        $a, 1
$tmp_1 = BEGIN_SILENCE
$var_3 = FETCH_R       'a'
$tmp_4 = POST_INC      $a
$tmp_5 = ADD           $var_3, $tmp_4
$var_2 = FETCH_W       'c'
         ASSIGN        $var_2, $tmp_5
         END_SILENCE   $tmp_1


, . -, BEGIN_SILENCE END_SILENCE . . -, $a $b FETCH_R ( ) FETCH_W ( ) .



, $a , .






CV , , .



. $a + $a++, :



<?php

$a = [1];
$c = $a[0] + $a[0]++;
var_dump($c); // int(2)


, , 3 2. , :



         ASSIGN        $a, [1]
$tmp_3 = FETCH_DIM_R   'a', 0
$var_4 = FETCH_DIM_RW  'a', 0
$tmp_5 = POST_INC      $var_4
$tmp_6 = ADD           $tmp_3, $tmp_5
         ASSIGN        $c, $tmp_6


, FETCH_DIM_R ( ) FETCH_DIM_RW ( /) .



, , , .



, . 3v4l.org.





- , :



  1. . .
  2. El operador @desactiva la optimización de CV y, como resultado, degrada el rendimiento. El operador es, @en principio, malo para el rendimiento.


~ nikic



Nota del traductor: como se mencionó anteriormente, @deshabilita las optimizaciones de CV solo en 5.x, en PHP 7 las optimizaciones de CV tienen lugar incluso en el caso de usar el operador de supresión de errores (pero tal vez esto no suceda en todos los casos). Nikita Popov tiene una publicación de blog interesante, Optimización estática en PHP 7 , en caso de que alguien quiera profundizar en el tema de la optimización.




All Articles