Rendimiento de variables dentro de cadenas en PHP

Tras la sorpresa de Rendimiento de constantes en PHP, os puedo adelantar que esta vez, probablemente lo hagáis de nuevo.

Se trata de concatenar variables a cadenas.

La primera forma, usa cadenas delimitadas por comillas simples, y el operador punto. La segunda usa el método heredado de Perl, de incluir las variables dentro del literal, naturalente, usando comillas dobles. La tercera, es igual que la primera, pero con comillas dobles, mientras que la cuarta y última, usa sprintf.

<?php
	$KI_MAX_ITER = 500000;
 
	$fInicio=microtime(true);
	for ($iCont=0; $iCont<$KI_MAX_ITER; $iCont++)
	{
		$sRes = 'Esta es la iteración número ' . $iCont . ' de ' . $KI_MAX_ITER . ' en el bucle.';
	}
	$fFin=microtime(true);
	echo ($fFin - $fInicio) . '<br>';
 
	$fInicio=microtime(true);
	for ($iCont=0; $iCont<$KI_MAX_ITER; $iCont++)
	{
		$sRes = "Esta es la iteración número $iCont de $KI_MAX_ITER en el bucle.";
	}
	$fFin=microtime(true);
	echo ($fFin - $fInicio) . '<br>';
 
	$fInicio=microtime(true);
	for ($iCont=0; $iCont<$KI_MAX_ITER; $iCont++)
	{
		$sRes = "Esta es la iteración número " . $iCont . " de " . $KI_MAX_ITER . " en el bucle.";
	}
	$fFin=microtime(true);
	echo ($fFin - $fInicio) . '<br>';
 
	$fInicio=microtime(true);
	for ($iCont=0; $iCont<$KI_MAX_ITER; $iCont++)
	{
		$sRes = sprintf('Esta es la iteración número %d de %d en el bucle.', $iCont, $KI_MAX_ITER);
	}
	$fFin=microtime(true);
	echo ($fFin - $fInicio) . '<br>';
?>

Los tiempos obtenidos han sido:
– 0.59406280517578
– 1.1006951332092
– 0.59988689422607
– 0.61792397499084

Con el primero y el tercero, se confirma lo ya visto en Composición de cadenas, que las comillas simples, son más veloces, al requerir menos proceso.

El segundo, es decir, incluir las variables dentro de los literales, es mi primera sorpresa, daba por sentado que sería eficiente y cómodo, aunque siempre lo descarté por poco legible. Pues no os engañéis, es además casi 2 veces más lento.

Sorprende por último el cuarto sistema, donde sprintf, es solamente apenas un 2% más lento que las otras.



10 comentarios en “Rendimiento de variables dentro de cadenas en PHP”

  1. Mis resultados… tal y como esperaba… las variables dentro del literal, lo mejor que funciona (PHP Version 5.3.2-1ubuntu4.5)

    0.34597396850586
    0.28382420539856
    0.33657002449036
    0.44441509246826

  2. No voy a publicar mis datos por no quedar en ridículo (es un PIII a 700, no se le puede pedir mucho ;D).

    Pero sobre las cadenas de texto si que puedo comentar un par de cosillas:
    Si queremos introducir un caracter de control, como el de línea nueva («\n») o tabulación («\t») tiene que ser una cadena de texto delimitada por comillas dobles de forma obligatoria.
    http://www.php.net/manual/en/language.types.string.php
    Note: Unlike the double-quoted and heredoc syntaxes, variables and escape sequences for special characters will not be expanded when they occur in single quoted strings.
    Lo mismo que se decia (no recuerdo si era en algún lugar de la documentación o era en otro lado) que las comillas simples eran más rápidas (además de más seguras), al realizar una salida de texto es más rápido realizar un echo que un print.
    También se aseguraba que era más eficiente, de cara a la salida de texto por la salida estandard, concatenar el texto mediante comas (sólo con echo) que mediante puntos. En realidad no se concatenan las cadenas, sino que echo permite separar los argumentos mediante comas… al no haber concatenación es lógico que sea más rápido.

    Hala, ya te he dado otra prueba que hacer ;D

  3. A mi me pasa como a Felipe. Comillas dobles con variables «inline» dentro de literales en comillas dobles es lo más rápido:

    ‘. 0.45502495765686
    » 0.42095613479614
    «{} 0.42870497703552
    «. 0.4633309841156
    sprintf 1.0427100658417

    También he añadio un test extra que resulta ligeramente más lento, mediendo las variables entre {} dentro del literal. Esto se puede hacer para llamar a posiciones de un array o a métodos de un objeto, por ejemplo.

  4. Por curiosidad, lo he ejecutado con APC por si hay diferencia. Al fin y al cabo APC «compila» PHP. Sí que hay cierta mejora, pero pequeña:

    ‘. 0.45911002159119
    » 0.411297082901
    «{} 0.42375993728638
    «. 0.45923900604248
    sprintf 1.0125269889832

    De hecho, mejora en todos los tests menos en el de las comillas simples :O

    ¿Cómo podemos explicar este comportamiento?

    En mi caso es una Ubuntu 10.10 con PHP 5.3.3

  5. Otra por curiosidad. Heredoc funciona igual de rápido que las comillas dobles:

    ‘. 0.44943404197693
    » 0.41568803787231
    «{} 0.40982890129089
    «. 0.4570209980011
    sprintf 1.0460708141327
    heredoc 0.41676616668701

    He definido la variable con: $sRes = <<<EOT
    Esta es la iteración número $iCont de $KI_MAX_ITER en el bucle.
    EOT;

  6. Personalmente la opción que más utilizo, por pensar que era la más eficiente es:

    «Variables dentro de comillas dobles {$variable}»

    Ahora me he quedado con la dura de si realmente es la opción más eficiente con PHP 5.2.x 🙁

  7. Probándolo con PHP 5.3.6, los resultados han sido los siguientes:
    – 0.45664286613464
    – 0.43342399597168
    – 0.47312498092651
    – 0.56699299812317

    En este entorno, las diferencias entre las 4 implementaciones quedan suavizadas, y se manifiesta como la alternativa más eficiente las variables dentro del literal, que era la opción más lenta con PHP 5.2.3.

    De forma análoga a lo que observasteis en Rendimiento de constantes en PHP, parece ser que todo haya cambiado en PHP 5.3, o bien que esas versiones iniciales de la rama 5.2 fueran bastante ineficientes.

  8. Creo recordar que el nacimiento de la rama 5 del PHP vino con algunas criticas por el rendimiento de la nueva rama… ahora no recuerdo si esas críticas eran ya desde la rama 5.0 o fue más tarde (con la rama 5.2, por ejemplo).

    Lo que es seguro es que la rama 5.3 era muy esperada porque venía con grandes mejoras, no sólo la velocidad.

    En la última versión, la 5.3.6 ha habido un cambio importante en los binarios generados: ya no hay binarios para windows con VC6, ya sólo hay binarios para windows hechos con VC8. Esto es así para simplificar la creación de los binarios así como implementar algunas mejoras (rendimiento, entre otras) que no se podian realizar con la compilación con VC6. El porqué se seguia manteniendo la compilación con VC6 es porque la compilación para windows de apache sólo es compatible con el php compilado con VC6.

    Debido a este cambio proyectos como XAMPP están preparando ya una versión con la compilación de apache bajo VC8.

    Un saludo

  9. Probando con el PHP-5.4.6:
    0.44080018997192
    0.39845395088196
    0.41323494911194
    0.42248797416687

    Y retomando el tema del Global vs Define:
    Global: 0.15020298957825
    Define: 0.18924713134766

    Saludos

  10. Fernando tus resultados siguen apoyando los de algunos comentarios de por aquí. Personalmente, sigue extrañándome que la segunda opción sea la más veloz, teniendo en cuenta que PHP en tiempo de ejecución debe resolver las variables incrustadas, y que por tanto deben tener un bytecode poco optimizado para permitirlo, pero es lo que es.

    En cuanto a global vs define, me sigue sorprendiendo la gran diferencia entre ambas, cuando a nivel de implementación interna, no debería haber tanta, pero sobretodo las discrepancias que hay entre tus resultados, los que obtuve yo, y los de otros comentarios en Rendimiento de constantes en PHP

Deja un comentario