
En cuanto a las micro optimizaciones de PHP, al reemplazar las comillas dobles con comillas simples, se rompen tantas copias que es bastante problemático hacer una nueva secuencia. Pero lo intentaré.
En este artículo solo habrá un punto de referencia, dónde estaría sin él, y el énfasis principal está en analizar cómo se organiza en su interior.
Descargo de responsabilidad
- Todo lo que se describe a continuación es, en su mayor parte, ahorrar en nanosegundos, y en la práctica no hará más que perder el tiempo perdido en dicha microoptimización. Esto es especialmente cierto para las "optimizaciones" del tiempo de compilación.
- Cortaré el código y la salida al máximo, dejando solo la esencia.
- Al escribir un artículo, usé PHP 7.2
Introductorio necesario
Una cadena entre comillas dobles
en la etapa de compilación se procesa de manera ligeramente diferente que una cadena entre comillas simples.
Las comillas simples se analizarán así:
statement -> expr -> scalar -> dereferencable_scalar -> T_CONSTANT_ENCAPSED_STRING
Doble así:
statement -> expr -> scalar -> '"' encaps_list '"' -> , ,
En los artículos sobre microoptimizaciones de PHP, a menudo se aconseja no utilizar
print , ya que es más lento que
echo . Veamos cómo están ordenados.
Analizando el
eco :
statement -> T_ECHO echo_expr_list -> echo_expr_list -> echo_expr -> expr
Impresión de análisis:
statement -> expr -> T_PRINT expr -> expr ( )
Es decir en general, sí, el
eco se detecta un paso antes y este paso, debe tenerse en cuenta, es bastante difícil.
Para no acentuar la atención una vez más durante el artículo, tendremos en cuenta que en la etapa de compilación las comillas dobles pierden las simples y la
impresión pierde
eco . Además, no olvidemos que, en el peor de los casos, se trata de nanosegundos.
Bueno, para no levantarse dos veces. Aquí están las funciones diff compilando
print y
echo :
1 - void zend_compile_print(znode *result, zend_ast *ast) 1 + void zend_compile_echo(zend_ast *ast) 2 2 { 3 3 zend_op *opline; 4 4 zend_ast *expr_ast = ast->child[0]; 5 5 6 6 znode expr_node; 7 7 zend_compile_expr(&expr_node, expr_ast); 8 8 9 9 opline = zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL); 10 - opline->extended_value = 1; 11 - 12 - result->op_type = IS_CONST; 13 - ZVAL_LONG(&result->u.constant, 1); 10 + opline->extended_value = 0; 14 11 }
Bueno, entiendes: tienen una funcionalidad idéntica, pero la
impresión adicionalmente devuelve una constante igual a 1. Creo que en este tema con la
impresión puedes cerrar y olvidarte de ella para siempre.
Línea simple, sin lujos
Las cadenas
echo 'Some string';
y
echo "Some string";
se dividirá casi idénticamente en 2 tokens (descargo de responsabilidad P2).
T_ECHO: echo T_ENCAPSED_AND_WHITESPACE/T_CONSTANT_ENCAPSED_STRING: "Some string"
Además, para las comillas simples siempre habrá T_CONSTANT_ENCAPSED_STRING, y para las comillas dobles, cuando sea así. Si hay un espacio en la línea, entonces T_ENCAPSED_AND_WHITESPACE.
Los códigos de operación serán fáciles de deshonrar y absolutamente idénticos:
line
Conclusiones
Si desea guardar un par de ciclos de procesador en la etapa de compilación, entonces, para cadenas constantes, use comillas simples.
Línea dinámica
Hay 4 opciones.
echo "Hello $name! Have a nice day!"; echo 'Hello '.$name.'! Have a nice day!'; echo 'Hello ', $name, '! Have a nice day!'; printf ('Hello %s! Have a nice day!', $name);
Para la primera opción:
T_ECHO: echo T_ENCAPSED_AND_WHITESPACE: Hello T_VARIABLE: $name T_ENCAPSED_AND_WHITESPACE: ! Have a nice day!
Para el segundo (también para el tercero, solo en lugar de puntos habrá comas):
T_ECHO: echo T_CONSTANT_ENCAPSED_STRING: 'Hello ' string: . T_VARIABLE: $name string: . T_CONSTANT_ENCAPSED_STRING: '! Have a nice day!'
Para el cuarto:
T_STRING: printf T_CONSTANT_ENCAPSED_STRING: 'Hello %s! Have a nice day!' string: , T_VARIABLE: $name
Pero con los códigos de operación todo será mucho más entretenido.
Primero:
echo "Hello $name! Have a nice day!"; line
Segundo:
echo 'Hello '.$name.'! Have a nice day!'; line
Tercero:
echo 'Hello ', $name, '! Have a nice day!'; line
Cuarto:
printf ('Hello %s! Have a nice day!', $name); line
El sentido común nos dice que la opción con `printf` perderá velocidad en los primeros tres (especialmente porque al final todavía hay el mismo ECHO), por lo que lo dejaremos para tareas donde se necesita formateo y no recordaremos más en este artículo.
Parece que la tercera opción es la más rápida: imprimir tres líneas seguidas sin concatenaciones, ROPE extrañas y la creación de variables adicionales. Pero no tan simple. La función de impresión en PHP ciertamente no es Rocket Science, pero de ninguna manera es un rendimiento de C-shny
banal .
A quién
le importa : la bola se desenreda comenzando con
php_output_write en el
archivo main / output.c .
CONCAT. Aquí todo es simple: convertimos, si es necesario, los argumentos en cadenas y creamos una nueva
zend_string usando
memcpy rápido. Lo único negativo es que con una larga cadena de concatenaciones para cada operación, se crearán nuevas líneas cambiando los mismos bytes de un lugar a otro.
Pero con ROPE_INIT, ROPE_ADD y ROPE_END todo es mucho más interesante. Sigue las manos:
- ROPE_INIT (ext = 3, return = ~ 3, operands = 'Hello +')
Asignamos la "cuerda" de tres ranuras (ext), colocamos la cadena 'Hola +' (operandos) en la ranura 0 y devolvemos la variable temporal ~ 3 (retorno) que contiene la "cuerda". - ROPE_ADD (ext = 1, return = ~ 3, operands = ~ 3 ,! 0)
Ponemos en la ranura 1 (ext) de la "cuerda" ~ 3 (operandos) la cadena 'Vasya', obtenida de la variable! 0 (operandos) y devolvemos la "cuerda" ~ 3 (retorno). - ROPE_END (ext = 2, return = ~ 2, operands = ~ 3, '% 21 + Have + a + nice + day% 21')
Ponemos la línea '% 21 + Have + a + nice + day% 21' (operandos) en la ranura 2 (ext), después de lo cual creamos una cadena zend_string del tamaño requerido y copiamos todas las ranuras de "cuerda" a la vez con la misma memoria .
Por separado, vale la pena señalar que, en el caso de constantes y variables temporales, los enlaces a los datos se colocarán en las ranuras, y no habrá copias innecesarias.
En mi opinión, bastante elegante. :)
Vamos a comparar. Como datos de origen, tomamos el archivo
zend_vm_execute.h (en mi humilde opinión, esto será cierto) para 71 mil líneas y lo imprimimos en 100 formas para 100 pases, eliminando el mínimo y el máximo (cada medición comenzó 10 veces, eligiendo la opción más común):
<?php $file = explode("\n", file_get_contents("C:\projects\C\php-src\Zend\zend_vm_execute.h")); $out = []; for ($c = 0; $c < 100; $c++) { $start = microtime(true); ob_start(); $i = 0; foreach ($file as $line) { $i++;
Que medimos | Tiempo promedio en segundos |
---|
"Cuerda" | 0,0129 |
Varios ECHO | 0,0135 |
Concatenación | 0,0158 |
printf , para completar | 0,0245 |
Conclusiones
- Para las cadenas con sustitución simple, de repente, las comillas dobles son más óptimas que las comillas simples con concatenación. Y cuanto más tiempo se usan las líneas, mayor es la ganancia.
- Argumentos separados por comas ... Hay muchos matices. Por medición, es más rápido que la concatenación y más lento que la "cuerda", pero hay demasiadas "variables" asociadas con la entrada / salida.
Conclusión
Es difícil para mí llegar a una situación en la que pueda surgir la necesidad de tales micro optimizaciones. Al elegir este o aquel enfoque, es más razonable guiarse por otros principios, por ejemplo, la legibilidad del código o el estilo de codificación adoptado por su empresa.
En cuanto a mí personalmente, no me gusta el enfoque de concatenación debido a la apariencia vyrviglazny, aunque en algunos casos puede estar justificado.
PD: si este tipo de análisis es interesante, hágamelo saber, hay mucho más que está lejos de ser siempre inequívoco y obvio: una variedad de objetos VS, VS para VS mientras VS para, su opción ... :)
Una pequeña explicación de leer comentarios
La sintaxis HEREDOC y las "cadenas complejas" (donde las variables están entre llaves) son las mismas cadenas con comillas dobles y se compilan exactamente de la misma manera.
Una mezcla de PHP con HTML como este:
<?php $name = 'Vasya';?>Hello <?=$name?>! Have a nice day!
Esto es solo 3
ecos seguidos.