Pregunta

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

¿Qué tal hacer esto?

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

Es $b una referencia a $a?

¿Fue útil?

Solución

Para la segunda parte de su pregunta, consulte la página del manual , que indica (citando)

  

asignación de matriz siempre implica valor   proceso de copiar. Utilice el operador de referencia a   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 tratar; -)

Considere este ejemplo de código:

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

$arr = array(10, 20);
my_func($arr);
var_dump($arr);

Se va a dar esta salida:

array
  0 => int 10
  1 => int 20

que indica la función no ha modificado la matriz "fuera" que se pasa como un parámetro:. Se pasa como una copia, y no una referencia

Si quieres que pasa por referencia, que tendrá que modificar la función, de esta manera:

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

Y la salida será:

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

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


No dude en leer el Explicación de la sección del manual: debe responder algunas de sus preguntas; -)

Otros consejos

En cuanto a su primera pregunta, la matriz se pasa por referencia a menos que sea modificada dentro del método / función que está llamando. Si intenta modificar la matriz dentro del método / función, una copia del mismo se hace primero, y luego se modifica sólo la copia. Esto hace que parezca como si la matriz se pasa por valor, cuando en realidad no lo es.

Por ejemplo, en este primer caso, a pesar de que no se está definiendo su función acepte $ my_array por referencia (utilizando el carácter & en la definición de parámetros), que todavía se pasa por referencia (es decir: usted don' memoria de residuos t 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 se modifica la matriz, una copia de la misma se hizo por primera vez (que utiliza más memoria, pero deja su matriz original no afectado).

function handle_array($my_array) {

    // ... modify $my_array
    $my_array[] = "New value";

    // ... $my_array effectively passed by value since requires local copy
}

FYI - esto se conoce como "copia perezoso" o "copia en escritura"

.

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 está marcado explícitamente como una referencia (con un signo comercial) => referencia explícita (tierra de usuario)

O esto:
- parámetro de matriz sin signo comercial:pasado por referencia;las operaciones de escritura alteran una nueva copia de la matriz, copia que se crea en la primera escritura;
- parámetro de matriz de signo comercial:pasado por referencia;las operaciones de escritura alteran la matriz original.

Recuerde: PHP hace una copia de valor en el momento en que escribes al parámetro de matriz sin signo comercial.eso es lo que copy-on-write medio.Me encantaría mostrarles la fuente C de este comportamiento, pero da miedo.Mejor uso xdebug_debug_zval().

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

Respuesta

Eso depende.

Versión larga

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

Siempre que la gente habla de referencias (o indicadores, para el caso), normalmente terminan en una logomaquia (basta con mirar esto). 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 tener razón al mismo tiempo, es mejor que les rompas la cabeza para encontrar una sola respuesta.

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

Como verá, todo el asunto del valor/por referencia está muy relacionado con qué 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")

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

Por defecto, los argumentos de la función son pasado por valor (de modo que si el El valor del argumento dentro de la función es cambió, no se pone cambiado fuera de la función).Para permitir que una función modificar su argumentos, deben ser pasado por referencia.

Para tener un argumento a un siempre pasada por referencia, anteponga un ampersand (&) a la función Nombre del argumento en la definición de la función

Hasta donde puedo decir, cuando los programadores grandes, serios y honestos hablan de referencias, generalmente hablan de alterando el valor de esa referencia.Y de 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".

Pero hay otro caso que no mencionan:¿Qué pasa si no cambio nada, solo leo?
¿Qué pasa 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, compañero de viaje.

¿Qué hace realmente PHP?(también conocido como "memoria")

Los mismos grandes y serios programadores, cuando se ponen aún más serios, hablan de "optimizaciones de memoria" en lo que respecta a las referencias.PHP también.Porque PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting, eso es por qué.

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, si esto realmente fuera un paso por valor, nos faltarían más de 3 MB de RAM, porque hay dos copias de esa matriz, ¿verdad?

Equivocado.Mientras no cambiemos el $arr variable, esa es una referencia, memoria.Simplemente no lo ves.Por eso PHP menciona tierra de usuario referencias cuando se habla de &$someVar, para distinguir entre internos y explícitos (con signo comercial).

Hechos

Entonces, when an array is passed as an argument to a method or function is it passed by reference?

se me ocurrio 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 está marcado explícitamente como una referencia (con un signo comercial)


En primer lugar, veamos cuánta memoria consume realmente esa matriz (ejecute aquí):

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

Esa cantidad de bytes.Excelente.

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

Ahora hagamos una función que solo lee dicha matriz como 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?¡Me sale 80! Ver por ti mismo.Esta es la parte que omite el manual de PHP.Si el $arr parámetro en realidad fue pasado por valor, verías algo similar a 1331840 bytes.Parece que $arr Se comporta como una referencia, ¿no?eso es porque es una referencia - una interna.

b) el método/función modifica el argumento de la matriz

Ahora vamos a escribir 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);

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

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

Ahora veamos cuanta memoria una operación de escritura a una referencia explícita toma (corre aquí) - observe el signo 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 obtendrás 200 como máximo!Entonces esto consume aproximadamente tanta memoria como lectura de un parámetro sin ampersand.

Por defecto

  1. Las primitivas se pasan por valor. Improbable que Java, cadena es primitiva en PHP
  2. Arrays de primitivas se pasan por valor
  3. Los objetos se pasan por referencia
  4. 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 una optimización, cada valor individual se pasa como referencia hasta su modificación dentro de la función. Si se modifica y se pasa el valor por referencia a continuación, se copia y se modifica la copia.

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

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, pero una copia de $a.

Al igual que el primer ejemplo, se puede hacer referencia $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);

Este hilo es un poco más viejo, pero aquí algo de lo que acaba de llegar a través de:

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 amplificador para el parámetro $ params y todavía se cambia el valor de $ matriz [ 'fecha']. Esto en realidad no coincide con todas las otras explicaciones aquí y lo que pensaba hasta ahora.

Si clonar los $ params [ 'fecha'] objeto, la segunda fecha emitida permanece igual. Si acaba de establecer en una cadena que no afecta a la salida tampoco.

En las matrices de PHP se pasan a las funciones por el valor por defecto, a menos que explicitamente pasarlos por referencia, como el siguiente fragmento de muestra:

$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)
}

Para extender una de las respuestas, también submatrices de matrices multidimensionales se pasan por valor a menos que explícitamente pasado por referencia.

<?php
$foo = array( array(1,2,3), 22, 33);

function hello($fooarg) {
  $fooarg[0][0] = 99;
}

function world(&$fooarg) {
  $fooarg[0][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

El resultado es:

array(3) {
  [0]=>
  array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
  [1]=>
  int(22)
  [2]=>
  int(33)
}
array(3) {
  [0]=>
  array(3) {
    [0]=>
    int(66)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
  [1]=>
  int(22)
  [2]=>
  int(33)
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top