1) Cuando una matriz se pasa como argumento a un método o función, ¿se pasa por referencia o por valor?
2) Al asignar una matriz a una variable, ¿la nueva variable es una referencia a la matriz original o es una copia nueva?
¿Qué hay de hacer esto?
$a = array(1,2,3);
$b = $a;
¿Es $b
una referencia a $a
?
Respuestas:
Para la segunda parte de su pregunta, consulte la página de matriz del manual , que establece (citando) :
Y el ejemplo dado:
Para la primera parte, la mejor manera de estar seguro es intentarlo ;-)
Considere este ejemplo de código:
Dará esta salida:
Lo que indica que la función no ha modificado la matriz "externa" que se pasó como parámetro: se pasa como una copia, y no como una referencia.
Si desea que se pase por referencia, deberá modificar la función de esta manera:
Y la salida se convertirá en:
Como, esta vez, la matriz se ha pasado "por referencia".
No dude en leer la sección de Referencias explicadas del manual: debe responder algunas de sus preguntas ;-)
fuente
&
, sí, debería - ver php.net/manual/en/…Con respecto a su primera pregunta, la matriz se pasa por referencia A MENOS QUE se modifique dentro del método / función que está llamando. Si intenta modificar la matriz dentro del método / función, primero se hace una copia y luego solo se modifica la copia. Esto hace que parezca que la matriz se pasa por valor cuando en realidad no lo es.
Por ejemplo, en este primer caso, aunque no esté definiendo su función para aceptar $ my_array por referencia (al usar el carácter & en la definición del parámetro), todavía se pasa por referencia (es decir, no desperdicia memoria) con una copia innecesaria).
Sin embargo, si modifica la matriz, primero se realiza una copia (que usa más memoria pero no afecta a su matriz original).
FYI: esto se conoce como "copia diferida" o "copia en escritura".
fuente
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 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:
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"):
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í ):
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:
¿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 los1331840
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:
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:
¡Mi apuesta es que obtienes 200 máx. Por lo tanto, esto consume aproximadamente tanta memoria como la lectura de un no-ampersand param .
fuente
Por defecto
Las matrices de objetos se pasan por valor (la matriz) pero cada objeto se pasa por referencia.
Nota: Como optimización, cada valor individual se pasa como referencia hasta que se modifique dentro de la función. Si se modifica y el valor se pasó por referencia, se copia y se modifica la copia.
fuente
Cuando una matriz se pasa a un método o función en PHP, se pasa por valor a menos que lo pase explícitamente por referencia, así:
En su segunda pregunta,
$b
no es una referencia$a
, sino una copia de$a
.Al igual que en el primer ejemplo, puede hacer referencia
$a
haciendo lo siguiente:fuente
Este hilo es un poco más antiguo pero aquí algo que acabo de encontrar:
Prueba este código:
http://codepad.viper-7.com/gwPYMw
Tenga en cuenta que no hay amplificador para el parámetro $ params y aún así cambia el valor de $ arr ['date']. Esto realmente no coincide con todas las otras explicaciones aquí y lo que pensé hasta ahora.
Si clono el objeto $ params ['date'], la segunda fecha de salida permanece igual. Si solo lo configuro en una cadena, tampoco afecta la salida.
fuente
Para ampliar una de las respuestas, también se pasan por valor las submatrices de matrices multidimensionales a menos que se pasen explícitamente por referencia.
El resultado es:
fuente
En PHP, las matrices se pasan a las funciones de forma predeterminada, a menos que las pase explícitamente como referencia, como muestra el siguiente fragmento:
Aquí está la salida:
fuente