tag name php performance types strong-typing php-7

php - get tag name wordpress



¿Son los tipos escalares y estrictos en PHP7 una característica que mejora el rendimiento? (2)

¿Hay algún beneficio de rendimiento al usar estas características? Si es así, ¿cómo?

Todavía no .

Pero este es el primer paso para una generación de código de operación más eficiente. Según RFC: Scalar Type Hints''s Scope ''s Future :

Debido a que las sugerencias de tipo escalar garantizan que un argumento pasado será de un cierto tipo dentro del cuerpo de una función (al menos inicialmente), esto podría usarse en el motor de Zend para optimizaciones. Por ejemplo, si una función toma dos argumentos insinuados y hace aritmética con ellos, no es necesario que los operadores aritméticos verifiquen los tipos de sus operandos.

En la versión anterior de php no había forma de saber qué tipo de parámetro se podía pasar a una función, lo que hace que sea realmente difícil tener un enfoque de compilación JIT para lograr un rendimiento superior, como lo hace HHVM de Facebook.

@ircmaxell en su blog menciona la posibilidad de llevar todo esto al siguiente nivel con una compilación nativa, lo que sería incluso mejor que el JIT.

Desde el punto de vista del rendimiento, las sugerencias de tipo escalar abren las puertas para implementar esas optimizaciones. Pero no mejora el rendimiento en sí mismo.

Desde PHP7 ahora podemos usar sugerencias de tipo escalar y solicitar tipos estrictos por archivo . ¿Hay algún beneficio de rendimiento al usar estas características? Si es así, ¿cómo?

Alrededor de los interwebs solo he encontrado beneficios conceptuales, tales como:

  • errores más precisos
  • evitar problemas con la coerción de tipo no deseado
  • Más código semántico, evitando malentendidos al usar el código de otros
  • Mejor evaluación IDE de código.

Hoy en día, el uso de tipos escalares y estrictos en PHP7 no mejora el rendimiento.

PHP7 no tiene un compilador JIT.

Si en algún momento en el futuro PHP obtiene un compilador JIT, no es demasiado difícil imaginar optimizaciones que podrían realizarse con la información de tipo adicional.

Cuando se trata de optimizaciones sin un JIT, los tipos escalares son solo parcialmente útiles.

Tomemos el siguiente código:

<?php function (int $a, int $b) : int { return $a + $b; } ?>

Este es el código generado por Zend para eso:

function name: {closure} L2-4 {closure}() /usr/src/scalar.php - 0x7fd6b30ef100 + 7 ops L2 #0 RECV 1 $a L2 #1 RECV 2 $b L3 #2 ADD $a $b ~0 L3 #3 VERIFY_RETURN_TYPE ~0 L3 #4 RETURN ~0 L4 #5 VERIFY_RETURN_TYPE L4 #6 RETURN null

ZEND_RECV es el código de operación que realiza la verificación de tipos y la coerción de los parámetros recibidos. El siguiente código de operación es ZEND_ADD :

ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; zval *op1, *op2, *result; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); fast_long_add_function(result, op1, op2); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); ZEND_VM_NEXT_OPCODE(); } } SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); } if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); } add_function(EX_VAR(opline->result.var), op1, op2); FREE_OP1(); FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); }

Sin entender lo que hace ese código, puedes ver que es bastante complejo.

Por lo tanto, el objetivo sería omitir ZEND_RECV completamente y reemplazar ZEND_ADD con ZEND_ADD_INT_INT que no necesita realizar ninguna comprobación (más allá de la protección) o bifurcación, porque se conocen los tipos de parámetros.

Para omitirlos y tener un ZEND_ADD_INT_INT , debe poder inferir de manera confiable los tipos de $b en el momento de la compilación. La inferencia del tiempo de compilación es a veces fácil, por ejemplo, $b son enteros o constantes literales.

Literalmente yesterday , PHP 7.1 obtuvo algo realmente similar: ahora hay controladores específicos para algunos ZEND_ADD alta frecuencia como ZEND_ADD . Opcache es capaz de inferir el tipo de algunas variables, incluso puede inferir los tipos de variables dentro de una matriz en algunos casos y cambiar los ZEND_ADD generados para usar el ZEND_ADD normal, para usar un controlador específico del tipo:

ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE)) { USE_OPLINE zval *op1, *op2, *result; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); result = EX_VAR(opline->result.var); ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); }

Nuevamente, sin entender lo que esto hace, puedes decir que esto es mucho más sencillo de ejecutar.

Estas optimizaciones son muy buenas, sin embargo, las optimizaciones más efectivas y más interesantes vendrán cuando PHP tenga un JIT.