TL; DR
a) el método / función solo lee el argumento de matriz => referencia implícita (interna)
b) el método / función modifica el argumento de matriz => valor
c) el argumento de matriz de método / función se marca explícitamente como una referencia (con un ampersand) => referencia explícita (usuario-tierra)
O esto:
- no-ampersand array param : pasado por referencia; las operaciones de escritura alteran una nueva copia de la matriz, copia que se crea en la primera escritura;
- ampersand array param : pasado por referencia; Las operaciones de escritura alteran la matriz original.
Recuerde: PHP realiza una copia de valor en el momento en que escribe en el parámetro de matriz no ampersand. Eso es lo que copy-on-write
significa. Me encantaría mostrarle la fuente C de este comportamiento, pero da miedo allí. Mejor use xdebug_debug_zval () .
Pascal MARTIN tenía razón. Kosta Kontos lo fue aún más.
Responder
Depende.
Versión larga
Creo que estoy escribiendo esto por mí mismo. Debería tener un blog o algo así ...
Cada vez que la gente habla de referencias (o punteros, para el caso), generalmente terminan en una logomaquia (¡solo mira este hilo !).
Como PHP es un lenguaje venerable, pensé que debería aumentar la confusión (aunque este es un resumen de las respuestas anteriores). Porque, aunque dos personas pueden estar en lo cierto al mismo tiempo, es mejor que simplemente quiebren sus cabezas en una sola respuesta.
En primer lugar, debes saber que no eres un pedante si no contestas en blanco y negro . Las cosas son más complicadas que "sí / no".
Como verá, todo lo relacionado con el valor / por referencia está muy relacionado con lo que está haciendo exactamente con esa matriz en su alcance de método / función: ¿leerlo o modificarlo?
¿Qué dice PHP? (también conocido como "cambio sabio")
El manual dice esto (énfasis mío):
Por defecto, los argumentos de la función se pasan por valor (de modo que si se cambia el valor del argumento dentro de la función , no se cambia fuera de la función). Para permitir que una función modifique sus argumentos, se deben pasar por referencia .
Para tener un argumento para una función siempre pasado por referencia, anteponga un signo de y comercial (&) al nombre del argumento en la definición de la función
Por lo que puedo decir, cuando los programadores grandes, serios y honestos con Dios hablan de referencias, generalmente hablan de alterar el valor de esa referencia . Y eso es exactamente lo que las conversaciones manuales sobre: hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value"
.
Sin embargo, hay otro caso que no mencionan: ¿qué pasa si no cambio nada, solo leo?
¿Qué sucede si pasa una matriz a un método que no marca explícitamente una referencia y no cambiamos esa matriz en el alcance de la función? P.ej:
<?php
function readAndDoStuffWithAnArray($array)
{
return $array[0] + $array[1] + $array[2];
}
$x = array(1, 2, 3);
echo readAndDoStuffWithAnArray($x);
Sigue leyendo, mi compañero de viaje.
¿Qué hace PHP realmente? (también conocido como "memoria sabia")
Los mismos programadores grandes y serios, cuando se vuelven aún más serios, hablan de "optimizaciones de memoria" con respecto a las referencias. También PHP. Porque PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting
, por eso .
No sería ideal pasar matrices ENORMES a varias funciones y PHP para hacer copias de ellas (después de todo, eso es lo que hace "pasar por valor"):
<?php
// filling an array with 10000 elements of int 1
// let's say it grabs 3 mb from your RAM
$x = array_fill(0, 10000, 1);
// pass by value, right? RIGHT?
function readArray($arr) { // <-- a new symbol (variable) gets created here
echo count($arr); // let's just read the array
}
readArray($x);
Bueno, ahora, si esto fuera realmente de paso por valor, habríamos perdido 3mb + RAM, porque hay dos copias de esa matriz, ¿verdad?
Incorrecto. Mientras no cambiemos la $arr
variable, es una referencia, en cuanto a memoria . Simplemente no lo ves. Es por eso que PHP menciona referencias de usuarios cuando se habla de ellas &$someVar
, para distinguir entre internas y explícitas (con ampersand).
Hechos
Entonces, when an array is passed as an argument to a method or function is it passed by reference?
Se me ocurrieron tres (sí, tres) casos:
a) el método / función solo lee el argumento de matriz
b) el método / función modifica el argumento de matriz
c) el argumento de matriz de método / función está explícitamente marcado como referencia (con un ampersand)
En primer lugar, veamos cuánta memoria realmente consume esa matriz (ejecutar aquí ):
<?php
$start_memory = memory_get_usage();
$x = array_fill(0, 10000, 1);
echo memory_get_usage() - $start_memory; // 1331840
Que muchos bytes. Excelente.
a) el método / función solo lee el argumento de matriz
Ahora hagamos una función que solo lea dicha matriz como argumento y veremos cuánta memoria toma la lógica de lectura:
<?php
function printUsedMemory($arr)
{
$start_memory = memory_get_usage();
count($arr); // read
$x = $arr[0]; // read (+ minor assignment)
$arr[0] - $arr[1]; // read
echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}
$x = array_fill(0, 10000, 1); // this is 1331840 bytes
printUsedMemory($x);
¿Quieres adivinar? ¡Tengo 80! Compruébalo por ti mismo . Esta es la parte que omite el manual de PHP. Si el $arr
parámetro realmente se pasara por valor, vería algo similar a los 1331840
bytes. Parece que se $arr
comporta como una referencia, ¿no? Eso es porque es una referencia interna.
b) el método / función modifica el argumento de matriz
Ahora, escribamos a ese parámetro, en lugar de leerlo:
<?php
function printUsedMemory($arr)
{
$start_memory = memory_get_usage();
$arr[0] = 1; // WRITE!
echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}
$x = array_fill(0, 10000, 1);
printUsedMemory($x);
Una vez más, ver por sí mismo , pero, para mí, que es bastante cerca de ser 1331840. Así que en este caso, la matriz está en realidad está copiando $arr
.
c) el argumento de matriz de método / función se marca explícitamente como una referencia (con un ampersand)
Ahora veamos cuánta memoria toma una operación de escritura en una referencia explícita (ejecute aquí ) - observe el ampersand en la firma de la función:
<?php
function printUsedMemory(&$arr) // <----- explicit, user-land, pass-by-reference
{
$start_memory = memory_get_usage();
$arr[0] = 1; // WRITE!
echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}
$x = array_fill(0, 10000, 1);
printUsedMemory($x);
¡Mi apuesta es que obtienes 200 máx. Por lo tanto, esto consume aproximadamente tanta memoria como la lectura de un no-ampersand param .