una referencia por parametros hacer funciones como asignar php arrays reference pass-by-reference pass-by-value

hacer - parametros por referencia php



¿Las matrices en PHP se pasan por valor o por referencia? (7)

Cuando una matriz se pasa como un argumento a un método o función, ¿se pasa por referencia?

¿Qué hay de hacer esto?

$a = array(1,2,3); $b = $a;

¿Es $b una referencia a $a ?


TL; DR

a) el método / función solo lee el argumento de la matriz => referencia implícita (interna)
b) el método / función modifica el argumento de la matriz => valor
c) el argumento de la matriz de método / función se marca explícitamente como una referencia (con un signo) => referencia explícita (usuario-tierra)

O esto:
- parámetro no-ampersand array : 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 no-ampersand array. Eso es lo que significa copy-on-write . Me encantaría mostrarte la fuente de C de este comportamiento, pero da miedo ahí. Mejor uso xdebug_debug_zval() .

Pascal MARTIN tenía razón. Kosta Kontos lo era aún más.

Responder

Depende.

Versión larga

Creo que estoy escribiendo esto para mí. Debería tener un blog o algo ...

Cada vez que las personas hablan de referencias (o indicadores, para el caso), por lo general terminan en una estomago (¡solo mire este thread !).
Dado que PHP es un lenguaje venerable, pensé que debía sumarme a 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 se agrieten en una sola respuesta.

En primer lugar, debes saber que no eres un pedante si no respondes de manera en blanco y negro . Las cosas son más complicadas que el "sí / no".

Como verá, todo lo relacionado con el valor / la referencia está muy relacionado con lo que está haciendo exactamente con esa matriz en el alcance de su método / función: ¿leerlo o modificarlo?

¿Qué dice PHP? (también conocido como "cambio sabio")

El manual dice esto (énfasis mío):

De forma predeterminada, los argumentos de la función se pasan por valor (de modo que si el valor del argumento dentro de la función se modifica , no se modifica 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 que siempre se pasa por referencia, anteponga un signo (&) al nombre del argumento en la definición de la función

Por lo que puedo decir, cuando los programadores grandes, serios, honestos a Dios hablan de referencias, generalmente hablan de alterar el valor de esa referencia . Y eso es exactamente de lo que habla el manual: 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 se pasa una matriz a un método que no marca explícitamente una referencia y no cambiamos esa matriz en el ámbito de la función? Aka:

<?php function printArray($array) {} $x = array(1); printArray($x);

Sigue leyendo, mi compañero de viaje.

¿Qué hace PHP en realidad? (también conocido como "memoria-sabio")

Los mismos grandes y serios programadores, cuando se ponen aún más serios, hablan de "optimizaciones de memoria" con respecto a las referencias. Lo mismo ocurre con PHP. Debido a que PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting , es php.net/manual/en/internals2.variables.intro.php .

No sería ideal pasar matrices GRANDES a varias funciones, y PHP para hacer copias de ellas (eso es lo que hace el "paso por valor", después de todo):

<?php // filling an array with 10000 elements of int 1 // let''s say it grabs 3 mb from you 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 realmente fue pasado por valor, tendríamos un poco de RAM de 3mb +, porque hay dos copias de esa matriz, ¿verdad?

Incorrecto. Mientras no cambiemos la variable $arr , eso es una referencia, en cuanto a memoria . Simplemente no lo ves. Es por eso que PHP xdebug_debug_zval() referencias de tierras de usuario cuando se habla de &$someVar , para distinguir entre las internas y las explícitas (con signo).

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 la matriz
b) el método / función modifica el argumento de la matriz
c) el argumento de la matriz de método / función se marca explícitamente como una referencia (con un signo)

En primer lugar, veamos cuánta memoria come esa matriz (ejecute here ):

<?php $start_memory = memory_get_usage(); $x = array_fill(0, 10000, 1); echo memory_get_usage() - $start_memory; // 1331840

Que muchos bytes. Genial.

a) el método / función solo lee el argumento de la matriz

Ahora hagamos una función que solo lea dicha matriz como un argumento y veremos cuánta memoria ocupa 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! Ver por ti mismo . Esta es la parte que omite el manual de PHP. Si el $arr se pasara por valor, 1331840 algo similar a 1331840 bytes. Parece que $arr comporta como una referencia, ¿no es así? Eso es porque es una referencia, una interna.

b) el método / función modifica el argumento de la 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);

Nuevamente, ver por ti mismo , pero, para mí, eso es bastante cerca de ser 1331840. Entonces, en este caso, la matriz se está copiando a $arr .

c) el argumento de la matriz de método / función se marca explícitamente como una referencia (con un signo)

Ahora veamos cuánta memoria lleva una operación de escritura a una referencia explícita (ejecute here ). Observe el signo en la firma de 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 max! Por lo tanto, esto consume aproximadamente tanta memoria como la lectura de un parámetro que no está en orden .


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 realiza una copia y, a continuación, 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 (usando el carácter & en la definición del parámetro), aún se pasa por referencia (es decir, no desperdicia memoria). con una copia innecesaria).

function handle_array($my_array) { // ... read from but do not modify $my_array print_r($my_array); // ... $my_array effectively passed by reference since no copy is made }

Sin embargo, si modifica la matriz, primero se realiza una copia (que utiliza más memoria pero no afecta a la matriz original).

function handle_array($my_array) { // ... modify $my_array $my_array[] = "New value"; // ... $my_array effectively passed by value since requires local copy }

Para su información, esto se conoce como "copia perezosa" o "copia en escritura".


Cuando se pasa una matriz a un método o función en PHP, se pasa por valor a menos que se la pase explícitamente por referencia, de esta manera:

function test(&$array) { $array[''new''] = ''hey''; } $a = $array(1,2,3); // prints [0=>1,1=>2,2=>3] var_dump($a); test($a); // prints [0=>1,1=>2,2=>3,''new''=>''hey''] var_dump($a);

En su segunda pregunta, $b no es una referencia a $a , sino una copia de $a .

Al igual que en el primer ejemplo, puede hacer referencia a $a haciendo lo siguiente:

$a = array(1,2,3); $b = &$a; // prints [0=>1,1=>2,2=>3] var_dump($b); $b[''new''] = ''hey''; // prints [0=>1,1=>2,2=>3,''new''=>''hey''] var_dump($a);


En PHP, las matrices se pasan a las funciones por valor de forma predeterminada, a menos que las pase por referencia explícitamente, como se muestra en el siguiente fragmento de código:

$foo = array(11, 22, 33); function hello($fooarg) { $fooarg[0] = 99; } function world(&$fooarg) { $fooarg[0] = 66; } hello($foo); var_dump($foo); // (original array not modified) array passed-by-value world($foo); var_dump($foo); // (original array modified) array passed-by-reference

Aquí está la salida:

array(3) { [0]=> int(11) [1]=> int(22) [2]=> int(33) } array(3) { [0]=> int(66) [1]=> int(22) [2]=> int(33) }


Este hilo es un poco más viejo pero aquí algo que acabo de encontrar:

Prueba este código:

$date = new DateTime(); $arr = [''date'' => $date]; echo $date->format(''Ymd'') . ''<br>''; mytest($arr); echo $date->format(''Ymd'') . ''<br>''; function mytest($params = []) { if (isset($params[''date''])) { $params[''date'']->add(new DateInterval(''P1D'')); } }

http://codepad.viper-7.com/gwPYMw

Tenga en cuenta que no hay ningún amplificador para el parámetro $ params y aún así cambia el valor de $ arr [''fecha'']. Esto realmente no coincide con todas las otras explicaciones aquí y lo que pensé hasta ahora.

Si clono el objeto $ params [''fecha''], la segunda fecha de salida seguirá siendo la misma. Si simplemente lo configuro en una cadena, tampoco afectará la salida.


Para la segunda parte de su pregunta, vea la página de la matriz del manual , que dice (cita) :

La asignación de matrices siempre implica la copia de valores. Utilice el operador de referencia para copiar una matriz por referencia.

Y el ejemplo dado:

<?php $arr1 = array(2, 3); $arr2 = $arr1; $arr2[] = 4; // $arr2 is changed, // $arr1 is still array(2, 3) $arr3 = &$arr1; $arr3[] = 4; // now $arr1 and $arr3 are the same ?>


Para la primera parte, la mejor manera de estar seguro es intentarlo ;-)

Considere este ejemplo de código:

function my_func($a) { $a[] = 30; } $arr = array(10, 20); my_func($arr); var_dump($arr);

Le dará esta salida:

array 0 => int 10 1 => int 20

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, tendrá que modificar la función, de esta manera:

function my_func(& $a) { $a[] = 30; }

Y la salida se convertirá en:

array 0 => int 10 1 => int 20 2 => int 30

Como, esta vez, la matriz se ha pasado "por referencia".


No dude en leer la sección Referencias explicadas del manual: debería responder algunas de sus preguntas ;-)


Por defecto

  1. Las primitivas se pasan por valor. Improbable para Java, la cadena es primitiva en PHP
  2. Las matrices de primitivas se pasan por valor.
  3. Los objetos se pasan por referencia
  4. Las matrices de objetos se pasan por valor (la matriz) pero cada objeto se pasa por referencia.

    <?php $obj=new stdClass(); $obj->field=''world''; $original=array($obj); function example($hello) { $hello[0]->field=''mundo''; // change will be applied in $original $hello[1]=new stdClass(); // change will not be applied in $original $ } example($original); var_dump($original); // array(1) { [0]=> object(stdClass)#1 (1) { ["field"]=> string(5) "mundo" } }

Nota: Como optimización, cada valor individual se pasa como referencia hasta que se modifica dentro de la función. Si se modifica y el valor se pasó por referencia, se copia y la copia se modifica.