Pregunta

En PHP, los parámetros de la función se pueden pasar por referencia anteponiendo un signo y el parámetro en la declaración de la función, de este modo:

function foo(&$bar)
{
    // ...
}

Ahora, soy consciente de que esto no es diseñado para mejorar el rendimiento, sino que permite que las funciones cambien las variables que normalmente están fuera de su alcance.

En cambio, PHP parece usar Copiar en escritura para evitar copiar objetos (y quizás también arreglos) hasta que se cambien. Por lo tanto, para las funciones que no cambian sus parámetros, el efecto debería ser el mismo que si los hubiera pasado por referencia.

Sin embargo, me preguntaba si la lógica de Copiar en escritura tal vez tenga un corto circuito en el paso por referencia y si eso tiene algún impacto en el rendimiento.

ETA: Para estar seguro, asumo que no es más rápido, y soy consciente de que no es para eso que están las referencias. Así que creo que mis conjeturas son bastante buenas, solo estoy buscando una respuesta de alguien que realmente sepa lo que definitivamente está sucediendo bajo el capó. En los cinco años de desarrollo de PHP, siempre me ha resultado difícil obtener información de calidad sobre las funciones internas de PHP sin tener que leer la fuente.

¿Fue útil?

Solución

El motor de Zend usa copia en escritura, y cuando usted usa una referencia, incurre en una pequeña sobrecarga adicional. Solo puedo encontrar esta mención al momento de escribir, sin embargo, y los comentarios en el manual contienen otros enlaces.

(EDITAR) La página del manual en Objetos y referencias contiene un poco más de información sobre cómo las variables de los objetos difieren de las referencias.

Otros consejos

En una prueba con 100 000 iteraciones de llamar a una función con una cadena de 20 kB, los resultados son:

Función que solo lee / usa el parámetro

pass by value:      0.12065005 seconds
pass by reference:  1.52171397 seconds

Función para escribir / cambiar el parámetro

pass by value:      1.52223396 seconds
pass by reference:  1.52388787 seconds

Conclusiones

  1. Pasar el parámetro por valor siempre es más rápido

  2. Si la función cambia el valor de la variable pasada, para fines prácticos es lo mismo que pasar por referencia que por valor

Hice una prueba al respecto porque no estaba seguro de las respuestas dadas.

Mis resultados muestran que pasar arrays o cadenas grandes por referencia es significativamente más rápido.

Aquí están mis resultados: Benchmark

El eje Y (Ejecuciones) es la cantidad de veces que se puede llamar a una función en 1 segundo * 10

La prueba se repitió 8 veces para cada función / variable

Y aquí están las variables que utilicé:

$large_array = array_fill(PHP_INT_MAX / 2, 1000, 'a');
$small_array = array('this', 'is', 'a', 'small', 'array');
$large_object = (object)$large_array;
$large_string = str_repeat('a', 100000);
$small_string = 'this is a small string';
$value = PHP_INT_MAX / 2;

Estas son las funciones:

function pass_by_ref(&$var) {
}

function pass_by_val($var) {
}

He experimentado con valores y referencias de una cadena de 10k bytes pasándola a dos funciones idénticas. Uno toma argumento por valor y el segundo por referencia. Eran funciones comunes: tomar argumentos, hacer un procesamiento simple y devolver un valor. Hice 100 000 llamadas de ambos y descubrí que las referencias no están diseñadas para aumentar el rendimiento; el beneficio de la referencia fue de cerca del 4-5% y crece solo cuando la cuerda se vuelve lo suficientemente grande (100k y más, lo que dio una mejora del 6-7%) . Por lo tanto, mi conclusión es que no utilice referencias para aumentar el rendimiento, esto no es para eso.

Utilicé PHP versión 5.3.1

Estoy bastante seguro de que no, no es más rápido. Además, dice específicamente en el manual que no intente usar referencias para aumentar el rendimiento.

Editar: no puedo encontrar lo que dice eso, ¡pero está ahí!

No hay nada mejor que un trozo de código de prueba

<?PHP
$r = array();

for($i=0; $i<500;$i++){
$r[]=5;
}

function a($r){
$r[0]=1;
}
function b(&$r){
$r[0]=1;
}

$start = microtime(true);
for($i=0;$i<9999;$i++){
  //a($r);
  b($r);
}
$end = microtime(true);

echo $end-$start;
?>

Resultado final! Cuanto mayor sea la matriz (o mayor el recuento de llamadas), mayor será la diferencia. Entonces, en este caso, la llamada por referencia es más rápida porque el valor se cambia dentro de la función.

De lo contrario, no hay una diferencia real entre " por referencia " y " por valor " ;, el compilador es lo suficientemente inteligente como para no crear una nueva copia cada vez que no sea necesario.

Traté de comparar esto con un ejemplo del mundo real basado en un proyecto en el que estaba trabajando. Como siempre, las diferencias son triviales, pero los resultados fueron algo inesperados. Para la mayoría de los puntos de referencia que he visto, la función llamada no cambia realmente el valor pasado. Realicé un simple str_replace () en él.

**Pass by Value Test Code:**

$originalString=''; // 1000 pseudo-random digits

function replace($string) {
    return str_replace('1', 'x',$string);
}
$output = '';
/* set start time */
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$tstart = $mtime;
set_time_limit(0);

for ($i = 0; $i < 10; $i++ ) {
    for ($j = 0; $j < 1000000; $j++) {
        $string = $originalString;
        $string = replace($string);
    }
}

/* report how long it took */
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$tend = $mtime;
$totalTime = ($tend - $tstart);
$totalTime = sprintf("%2.4f s", $totalTime);
$output .= "\n" . 'Total Time' .
    ': ' . $totalTime;
$output .= "\n" . $string;
echo $output;

Pase por código de prueba de referencia

Lo mismo a excepción de

function replace(&$string) {
    $string = str_replace('1', 'x',$string);
}
/* ... */
replace($string);

Resultados en segundos (10 millones de iteraciones):

PHP 5
    Value:     14.1007
    Reference: 11.5564

PHP 7
    Value:     3.0799
    Reference: 2.9489

La diferencia es una fracción de milisegundo por llamada de función, pero para este caso de uso, pasar por referencia es más rápido tanto en PHP 5 como en PHP 7.

(Nota: las pruebas de PHP 7 se realizaron en una máquina más rápida: PHP 7 es más rápido, pero probablemente no mucho más rápido).

Es simple, no hay necesidad de probar nada. Depende del caso de uso.

Pasar por valor SIEMPRE SERÁ MÁS RÁPIDO POR VALOR que la referencia para una pequeña cantidad de argumentos. Esto depende de cuántas variables permita la arquitectura pasar a través de los registros (ABI).

Por ejemplo, x64 le permitirá que se pasen 4 valores de 64 bits cada uno a través de los registros. https://en.wikipedia.org/wiki/X86_calling_conventions

Esto se debe a que no tiene que anular la referencia de los punteros, simplemente use el valor directamente.

Si los datos que se deben pasar son más grandes que ABI, el resto de los valores se acumularán. En este caso, una matriz o un objeto (que en instancia es una clase, o una estructura + encabezados) SIEMPRE SERÁ MÁS RÁPIDO POR REFERENCIA.

Esto se debe a que una referencia es solo un puntero a sus datos (no a los datos en sí), tamaño fijo, por ejemplo, 32 o 64 bits, según la máquina. Ese puntero cabrá en un registro de CPU.

PHP está escrito en C / C ++, por lo que espero que se comporte de la misma manera.

No es necesario agregar & amp; Operador al pasar objetos. En PHP 5+ los objetos se pasan por referencia de todos modos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top