1) Quando uma matriz é passada como argumento para um método ou função, é passada por referência ou por valor?
2) Ao atribuir uma matriz a uma variável, a nova variável é uma referência à matriz original ou é uma nova cópia?
Que tal fazer isso:
$a = array(1,2,3);
$b = $a;
É $b
uma referência a $a
?
Respostas:
Para a segunda parte da sua pergunta, consulte a página da matriz do manual , que declara (citando) :
E o exemplo dado:
Para a primeira parte, a melhor maneira de ter certeza é tentar ;-)
Considere este exemplo de código:
Isso dará a saída:
O que indica que a função não modificou a matriz "externa" que foi passada como parâmetro: é passada como uma cópia e não como uma referência.
Se você deseja que seja passado por referência, terá que modificar a função, desta maneira:
E a saída se tornará:
Como, desta vez, a matriz foi passada "por referência".
Não hesite em ler a seção Referências explicadas do manual: ele deve responder a algumas de suas perguntas ;-)
fonte
&
, sim, ele deveria - veja php.net/manual/en/…Com relação à sua primeira pergunta, o array é passado por referência, a menos que seja modificado no método / função que você está chamando. Se você tentar modificar a matriz dentro do método / função, uma cópia dela será feita primeiro e somente a cópia será modificada. Isso faz parecer que a matriz é passada por valor quando na verdade não é.
Por exemplo, neste primeiro caso, mesmo que você não esteja definindo sua função para aceitar $ my_array por referência (usando o caractere & na definição de parâmetro), ela ainda será passada por referência (por exemplo: você não desperdiça memória com uma cópia desnecessária).
No entanto, se você modificar a matriz, uma cópia dela será feita primeiro (que usa mais memória, mas deixa a matriz original inalterada).
Para sua informação, isso é conhecido como "cópia lenta" ou "cópia na gravação".
fonte
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):
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:
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):
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 ):
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:
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 aos1331840
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:
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:
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 .
fonte
Por padrão
Matrizes de objetos são passadas por valor (a matriz), mas cada objeto é passado por referência.
Nota: Como uma otimização, todos os valores são passados como referência até serem modificados dentro da função. Se ele foi modificado e o valor foi passado por referência, é copiado e a cópia é modificada.
fonte
Quando uma matriz é passada para um método ou função no PHP, é passada por valor, a menos que você a passe explicitamente por referência, da seguinte maneira:
Na sua segunda pergunta,
$b
não é uma referência a$a
, mas uma cópia de$a
.Muito parecido com o primeiro exemplo, você pode
$a
fazer referência fazendo o seguinte:fonte
Esta discussão é um pouco mais antiga, mas aqui algo que me deparei:
Tente este código:
http://codepad.viper-7.com/gwPYMw
Observe que não há amplificador para o parâmetro $ params e ainda assim altera o valor de $ arr ['date']. Isso realmente não combina com todas as outras explicações aqui e o que eu pensava até agora.
Se eu clonar o objeto $ params ['date'], a segunda data de saída permanecerá a mesma. Se eu apenas configurá-lo como uma string, também não afeta a saída.
fonte
Para estender uma das respostas, também as sub-matrizes de matrizes multidimensionais são passadas por valor, a menos que sejam explicitamente passadas por referência.
O resultado é:
fonte
Em matrizes PHP, são passadas para funções por valor, por padrão, a menos que você as passe explicitamente por referência, como mostra o seguinte trecho:
Aqui está a saída:
fonte