TL; DR
a) o método / função lê apenas o argumento da matriz => referência implícita (interna)
b) o método / função modifica o argumento da matriz => valor
c) o argumento da matriz do método / função é explicitamente marcado como uma referência (com um e comercial) => referência explícita (terra do usuário)
Ou isto:
- parâmetro não comercial e comercial : passado por referência; as operações de gravação alteram uma nova cópia da matriz, cópia criada na primeira gravação;
- e comercial array param : passado por referência; as operações de gravação alteram a matriz original.
Lembre-se - o PHP faz uma cópia de valor no momento em que você escreve no parâmetro da matriz não comercial. É isso que copy-on-write
significa. Eu adoraria mostrar a fonte C desse comportamento, mas é assustador lá. Melhor usar xdebug_debug_zval () .
Pascal MARTIN estava certo. Kosta Kontos foi ainda mais.
Responda
Depende.
Versão longa
Acho que estou escrevendo isso para mim. Eu deveria ter um blog ou algo assim ...
Sempre que as pessoas falam de referências (ou ponteiros, na verdade), elas geralmente acabam em um logotipo (apenas olhe para este tópico !).
Sendo o PHP uma linguagem venerável, pensei que deveria aumentar a confusão (mesmo que este seja um resumo das respostas acima). Porque, embora duas pessoas possam estar certas ao mesmo tempo, é melhor você apenas quebrar a cabeça em uma resposta.
Primeiro, você deve saber que não é pedante se não responder de maneira em preto e branco . As coisas são mais complicadas do que "sim / não".
Como você verá, todo o valor por referência / referência está muito relacionado ao que exatamente você está fazendo com essa matriz no seu escopo de método / função: lendo ou modificando?
O que o PHP diz? (também conhecido como "alteração")
O manual diz o seguinte (ênfase minha):
Por padrão, os argumentos da função são passados por valor (para que, se o valor do argumento dentro da função for alterado , ele não seja alterado fora da função). Para permitir que uma função modifique seus argumentos, eles devem ser passados por referência .
Para ter um argumento para uma função sempre passada por referência, coloque um e comercial (&) no nome do argumento na definição da função
Até onde eu sei, quando grandes programadores sérios e honestos falam sobre referências, geralmente falam em alterar o valor dessa referência . E isso é exatamente o que as negociações manuais sobre: hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value"
.
Há outro caso que eles não mencionam: e se eu não mudar nada - apenas leia?
E se você passar uma matriz para um método que não marca explicitamente uma referência e não alteramos essa matriz no escopo da função? Por exemplo:
<?php
function readAndDoStuffWithAnArray($array)
{
return $array[0] + $array[1] + $array[2];
}
$x = array(1, 2, 3);
echo readAndDoStuffWithAnArray($x);
Continue lendo, meu companheiro de viagem.
O que o PHP realmente faz? (também conhecido como "memória")
Os mesmos programadores grandes e sérios, quando ficam ainda mais sérios, falam sobre "otimizações de memória" em relação às referências. O mesmo acontece com o PHP. Porque PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting
é por isso .
Não seria ideal passar matrizes ENORME para várias funções, e o PHP para fazer cópias delas (afinal, o que "passa por valor" faz):
<?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);
Bem, agora, se isso realmente foi passado por valor, teríamos mais de 3 MB + RAM, porque existem duas cópias dessa matriz, certo?
Errado. Contanto que não alteremos a $arr
variável, isso é uma referência em memória . Você simplesmente não vê. É por isso que o PHP menciona referências de terra do usuário ao falar sobre &$someVar
, para distinguir entre internas e explícitas (com e comercial).
Fatos
Assim, when an array is passed as an argument to a method or function is it passed by reference?
Eu vim com três (sim, três) casos:
a) o método / função lê apenas o argumento da matriz
b) o método / função modifica o argumento da matriz
c) o argumento da matriz do método / função é explicitamente marcado como uma referência (com um e comercial)
Primeiro, vamos ver quanta memória esse array realmente consome (execute aqui ):
<?php
$start_memory = memory_get_usage();
$x = array_fill(0, 10000, 1);
echo memory_get_usage() - $start_memory; // 1331840
Que muitos bytes. Ótimo.
a) o método / função lê apenas o argumento do array
Agora vamos criar uma função que apenas leia o referido array como argumento e veremos quanta memória a lógica de leitura leva:
<?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);
Quer adivinhar? Eu tenho 80! Veja você mesmo . Esta é a parte que o manual do PHP omite. Se o $arr
parâmetro fosse realmente passado por valor, você veria algo semelhante aos 1331840
bytes. Parece que $arr
se comporta como uma referência, não é? Isso porque é uma referência - interna.
b) o método / função modifica o argumento do array
Agora, vamos escrever para esse parâmetro, em vez de ler:
<?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);
Mais uma vez, veja por si mesmo , mas, para mim, isso é muito próximo de 1331840. Portanto, nesse caso, a matriz está realmente sendo copiada $arr
.
c) o argumento de matriz de método / função é explicitamente marcado como uma referência (com um e comercial)
Agora vamos ver quanta memória uma operação de gravação leva a uma referência explícita (execute aqui ) - observe oe comercial na assinatura da função:
<?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);
Minha aposta é que você receba 200 no máximo! Portanto, isso consome aproximadamente a mesma quantidade de memória que a leitura de um parâmetro que não seja E comercial .