As variáveis ​​do PHP são passadas por valor ou por referência?

Respostas:

312

É pelo valor de acordo com a documentação do PHP .

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.

<?php
function add_some_extra(&$string)
{
    $string .= 'and something extra.';
}

$str = 'This is a string, ';
add_some_extra($str);
echo $str;    // outputs 'This is a string, and something extra.'
?>
Michael Stum
fonte
4
Eu também tinha essa dúvida (novato) - então, para ficar claro, isso seria o mesmo que $str = add_some_extra($str);se eu não estivesse usando a referência, certo? então qual é o verdadeiro valor agregado disso?
Obmerk Kronen
7
@Obmerk Se você não estivesse usando o e comercial para significar por referência, não seria equivalente. Observe como a função não possui declaração de retorno, portanto, $strseria atribuída nula, no seu caso.
The Unknown Dev
se você fizer dessa maneira @ObmerkKronen, terá que retornar o valor e capturá-lo também através do seu código. A variável inicial permanecerá a mesma, caso contrário.
Nabeel Khan 04/04
Gostaria de saber se o passe por referência tem alguns benefícios de desempenho ou não? Estou passando uma grande matriz e, por padrão, é passar por valor. Então, se eu usar a chamada por referência, haverá algum benefício em termos de desempenho ??? (mantendo os valores da matriz inalterados durante todo o processo)
Choxx 8/16
4
o benefício real é que você pode manipular / retornar valores múltiplos. Você também pode passar variáveis ​​por referência e ainda permitir que a função retorne algo.
Martin Schneider
65

No PHP, por padrão, os objetos são passados ​​como cópia de referência para um novo Objeto.

Veja este exemplo .............

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue($obj)
  {
   $obj->abc = 30;
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 30

Agora veja isso ..............

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue($obj)
  {
    $obj = new Y();
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 10 not 20 same as java does.

Agora veja isso ..............

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue(&$obj)
  {
    $obj = new Y();
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 20 not possible in java.

Espero que você possa entender isso.

hardik
fonte
1
Isso ilustra muito bem como o objeto PHP lida com obras.
Frederik Krautwald
2
1ª ex, o valor da referência do obj é passado para a função, as alterações no obj usando a nova referência serão refletidas em todas as outras referências apontando para o mesmo obj. 2nd ex, novamente o VALUE da referência do obj é passado para a função, a função está alterando o valor da referência para apontar para um novo obj, o antigo obj permanece o mesmo. 3rd ex, a referência do valor da referência do obj é passada para a função, portanto as alterações na função estão operando no mesmo obj.
S-hunter
Exemplos perfeitos e exatamente o que eu pensei que aconteceria. Sou iniciante no PHP (a partir do Javascript / node.js) e às vezes é difícil entender o que está acontecendo, mas isso é muito claro!
TKoL 13/05/19
Este exemplo é desnecessariamente complicado. $ynão é necessário - não há nada function changeValueque exija que ele esteja dentro class Y, para que emaranhe dois conceitos não relacionados. Eu mudaria function changeValuepara o escopo externo, logo acima $x = new X();. Remova todas as referências a $y. Agora é mais fácil ver que os dois primeiros exemplos deixam $ x em paz e o terceiro altera seu conteúdo para new Y(). O que seria mais fácil para ver se você jogou o typede $x- o fato de que tanto Xe Yacontecer para incluir um $abccampo também é irrelevante para o que é demonstrado
ToolmakerSteve
60

Parece que muitas pessoas ficam confusas com a maneira como os objetos são passados ​​para as funções e o que passa por referência. As variáveis ​​de objeto ainda são passadas por valor, apenas o valor que é passado no PHP5 é um identificador de referência. Como prova:

<?php
class Holder {
    private $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function getValue() {
        return $this->value;
    }
}

function swap($x, $y) {
    $tmp = $x;
    $x = $y;
    $y = $tmp;
}

$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);

echo $a->getValue() . ", " . $b->getValue() . "\n";

Saídas:

a, b

Para passar por referência , podemos modificar as variáveis ​​que são vistas pelo chamador. Que claramente o código acima não funciona. Precisamos mudar a função de swap para:

<?php
function swap(&$x, &$y) {
    $tmp = $x;
    $x = $y;
    $y = $tmp;
}

$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);

echo $a->getValue() . ", " . $b->getValue() . "\n";

Saídas:

b, a

para passar por referência.

grom
fonte
18
Eu acho que essa prova é uma má interpretação. Parece que você estava tentando trocar referências. Você tem um problema com a forma como os objetos são atribuídos. Você está reatribuindo a referência que é imutável. É o valor que aponta para que pode ser alterado de dentro. A redefinição de swap agora está passando ** x, o que permite alterar * x. O problema é pensar que $ x = $ y mudaria o que $ x aponta originalmente.
grantwparks
9
Isto não é uma prova . A saída do primeiro exemplo é exatamente o que você esperaria se o valor atual de todo o objeto fosse passado para a swapfunção; em outras palavras, se os objetos fossem "passados ​​por valor". Por outro lado, também é exatamente o que você esperaria se um identificador de objeto fosse passado para a função, que é realmente o que acontece. Seu código não faz distinção entre esses dois casos.
EML
31

http://www.php.net/manual/en/migration5.oop.php

No PHP 5, há um novo modelo de objeto. O manuseio de objetos pelo PHP foi completamente reescrito, permitindo melhor desempenho e mais recursos. Nas versões anteriores do PHP, os objetos eram manipulados como tipos primitivos (por exemplo, números inteiros e seqüências de caracteres). A desvantagem desse método era que semanticamente todo o objeto foi copiado quando uma variável foi atribuída ou passada como parâmetro para um método. Na nova abordagem, os objetos são referenciados por identificador, e não por valor (pode-se pensar em um identificador como o identificador de um objeto).

Karl Seguin
fonte
25

As variáveis ​​PHP são atribuídas por valor, passadas para funções por valor, e quando os objetos que contêm / representam são passados ​​por referência. Você pode forçar as variáveis ​​a passar por referência usando um &

Atribuído por exemplo de valor / referência:

$var1 = "test";
$var2 = $var1;
$var2 = "new test";
$var3 = &$var2;
$var3 = "final test";

print ("var1: $var1, var2: $var2, var3: $var3);

produziria

var1: teste, var2: teste final, var3: teste final

Aprovado no exame de valor / referência:

$var1 = "foo";
$var2 = "bar";

changeThem($var1, $var2);

print "var1: $var1, var2: $var2";

function changeThem($var1, &$var2){
    $var1 = "FOO";
    $var2 = "BAR";
}

produziria:

var1: foo, var2 BAR

Variáveis ​​de objeto aprovadas pelo exemplo de referência:

class Foo{
    public $var1;

    function __construct(){
        $this->var1 = "foo";
    }

    public function printFoo(){
        print $this->var1;
    }
}


$foo = new Foo();

changeFoo($foo);

$foo->printFoo();

function changeFoo($foo){
    $foo->var1 = "FOO";
}

Saída:

FOO

(esse último exemplo poderia ser melhor provavelmente ...)

cmcculloh
fonte
2
"Objetos" não são valores no PHP5 e não podem ser "passados". O valor de $fooé um ponteiro para um objeto . $fooé passado por valor para a função changeFoo(), pois changeFoo()não declarou seu parâmetro com a &.
Newacct 01/10
9

Você pode passar uma variável para uma função por referência. Esta função poderá modificar a variável original.

Você pode definir a passagem por referência na definição da função:

<?php
function changeValue(&$var)
{
    $var++;
}

$result=5;
changeValue($result);

echo $result; // $result is 6 here
?>
Mahsin
fonte
6

Você pode fazer isso de qualquer maneira.

coloque um símbolo '&' na frente e a variável que você está passando passa a ser a mesma de sua origem. ou seja: você pode passar por referência, em vez de fazer uma cópia.

tão

    $fred = 5;
    $larry = & $fred;
    $larry = 8;
    echo $fred;//this will output 8, as larry and fred are now the same reference.
Bingy
fonte
2
Isso foi descontinuado e gera um aviso #
fijiaaron
5

Variáveis ​​contendo tipos primitivos são passadas por valor no PHP5. Variáveis ​​que contêm objetos são passadas por referência. Há um artigo bastante interessante do Linux Journal de 2006 que menciona essa e outras diferenças OO entre 4 e 5.

http://www.linuxjournal.com/article/9170

Polsonby
fonte
Todas as variáveis ​​são passadas por valor no PHP se o parâmetro da função não tiver &.
Newacct 01/10
1

Objetos são passados ​​por referência no PHP 5 e por valor no PHP 4. Variáveis ​​são passadas por valor por padrão!

Leia aqui: http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html

Miha
fonte
"Objetos" não são valores no PHP5 e não podem ser "passados". Todas as variáveis ​​são passadas por valor se o parâmetro da função passada para não tiver &.
Newacct 01/10
@newacct não é bem assim? Os objetos são um pouco passados ​​por referência . Eu acho que observei que objetos php podem ser modificados por funções, mesmo quando não definidos &na frente dos parâmetros na definição - se eles foram passados ​​por valor, o objeto contido no escopo que chamou a função com ele como parâmetro não seja afetado.
Félix Gagnon-Grenier
3
@ FélixGagnon-Grenier: Novamente, "objetos" não são valores e não podem ser "passados". Você não pode ter uma "variável" no PHP5 cujo valor seja um "objeto", você só pode ter um valor que seja uma referência a um objeto (isto é, um ponteiro para um objeto). É claro que você pode passar ou atribuir um ponteiro a um objeto por valor e modificar o objeto para o qual aponta, chamando um método que faz essa modificação. Isso não tem nada a ver com passagem por referência. Que tipo de valor é e se um parâmetro é transmitido por valor / transmitido por referência são coisas independentes e ortogonais.
precisa saber é o seguinte
1
class Holder
{
    private $value;

    public function __construct( $value )
    {
        $this->value = $value;
    }

    public function getValue()
    {
        return $this->value;
    }

    public function setValue( $value )
    {
        return $this->value = $value;
    }
}

class Swap
{       
    public function SwapObjects( Holder $x, Holder $y )
    {
        $tmp = $x;

        $x = $y;

        $y = $tmp;
    }

    public function SwapValues( Holder $x, Holder $y )
    {
        $tmp = $x->getValue();

        $x->setValue($y->getValue());

        $y->setValue($tmp);
    }
}


$a1 = new Holder('a');

$b1 = new Holder('b');



$a2 = new Holder('a');

$b2 = new Holder('b');


Swap::SwapValues($a1, $b1);

Swap::SwapObjects($a2, $b2);



echo 'SwapValues: ' . $a2->getValue() . ", " . $b2->getValue() . "<br>";

echo 'SwapObjects: ' . $a1->getValue() . ", " . $b1->getValue() . "<br>";

Os atributos ainda são modificáveis ​​quando não são passados ​​por referência, portanto, tenha cuidado.

Resultado:

SwapObjects: b, a SwapValues: a, b

Ricardo Saracino
fonte
1

Para quem se deparar com isso no futuro, quero compartilhar esta gema dos documentos PHP, publicados por um usuário anônimo :

Parece haver alguma confusão aqui. A distinção entre ponteiros e referências não é particularmente útil. O comportamento em alguns dos exemplos "abrangentes" já publicados pode ser explicado em termos unificadores mais simples. O código de Hayley, por exemplo, está fazendo EXATAMENTE o que você deveria esperar. (Usando> = 5.3)

Primeiro princípio: Um ponteiro armazena um endereço de memória para acessar um objeto. Sempre que um objeto é atribuído, um ponteiro é gerado. (Ainda não mergulhei profundamente no mecanismo do Zend, mas, tanto quanto posso ver, isso se aplica)

Segundo princípio e fonte da maior confusão: A passagem de uma variável para uma função é feita por padrão como uma passagem de valor, ou seja, você está trabalhando com uma cópia. "Mas os objetos são passados ​​por referência!" Um equívoco comum aqui e no mundo Java. Eu nunca disse uma cópia do quê. A passagem padrão é feita por valor. Sempre. O que está sendo copiado e passado, no entanto, é o ponteiro. Ao usar o "->", é claro que você acessará os mesmos componentes internos da variável original na função de chamada. Basta usar "=" para reproduzir apenas cópias.

Terceiro princípio: "&" define automaticamente e permanentemente outro nome / ponteiro de variável para o mesmo endereço de memória que qualquer outra coisa até que você os dissocie. É correto usar o termo "alias" aqui. Pense nisso como juntar dois ponteiros no quadril até separar à força com "unset ()". Essa funcionalidade existe no mesmo escopo e quando um argumento é passado para uma função. Freqüentemente, o argumento passado é chamado de "referência", devido a certas distinções entre "passagem por valor" e "passagem por referência", que eram mais claras em C e C ++.

Apenas lembre-se: ponteiros para objetos, não objetos em si, são passados ​​para funções. Esses ponteiros são CÓPIAS do original, a menos que você use "&" na sua lista de parâmetros para realmente passar os originais. Somente quando você vasculha as partes internas de um objeto os originais são alterados.

E aqui está o exemplo que eles fornecem:

<?php

//The two are meant to be the same
$a = "Clark Kent"; //a==Clark Kent
$b = &$a; //The two will now share the same fate.

$b="Superman"; // $a=="Superman" too.
echo $a;
echo $a="Clark Kent"; // $b=="Clark Kent" too.
unset($b); // $b divorced from $a
$b="Bizarro";
echo $a; // $a=="Clark Kent" still, since $b is a free agent pointer now.

//The two are NOT meant to be the same.
$c="King";
$d="Pretender to the Throne";
echo $c."\n"; // $c=="King"
echo $d."\n"; // $d=="Pretender to the Throne"
swapByValue($c, $d);
echo $c."\n"; // $c=="King"
echo $d."\n"; // $d=="Pretender to the Throne"
swapByRef($c, $d);
echo $c."\n"; // $c=="Pretender to the Throne"
echo $d."\n"; // $d=="King"

function swapByValue($x, $y){
$temp=$x;
$x=$y;
$y=$temp;
//All this beautiful work will disappear
//because it was done on COPIES of pointers.
//The originals pointers still point as they did.
}

function swapByRef(&$x, &$y){
$temp=$x;
$x=$y;
$y=$temp;
//Note the parameter list: now we switched 'em REAL good.
}

?>

Escrevi um post extenso e detalhado sobre este assunto para JavaScript , mas acredito que se aplica igualmente bem ao PHP, C ++ e qualquer outra linguagem em que as pessoas pareçam estar confusas sobre passagem por valor versus passagem por referência.

Claramente, PHP, como C ++, é uma linguagem que suporta passagem por referência. Por padrão, os objetos são passados ​​por valor. Ao trabalhar com variáveis ​​que armazenam objetos, ajuda a vê-las como ponteiros (porque é fundamentalmente o que elas são no nível da montagem). Se você passar um ponteiro por valor, ainda poderá "rastrear" o ponteiro e modificar as propriedades do objeto que está sendo apontado. O que você não pode fazer é apontar para um objeto diferente. Somente se você declarar explicitamente um parâmetro como sendo passado por referência, poderá fazer isso.

AleksandrH
fonte
0

Na verdade, ambos os métodos são válidos, mas isso depende de sua exigência. Os valores de passagem por referência geralmente tornam seu script lento. Portanto, é melhor passar variáveis ​​por valor considerando o tempo de execução. Além disso, o fluxo de código é mais consistente quando você passa variáveis ​​por valor.

atif
fonte
0

Use isso para funções quando desejar simplesmente alterar a variável original e retorná-la novamente ao mesmo nome de variável com seu novo valor atribuído.

function add(&$var){ // The &amp; is before the argument $var
   $var++;
}
$a = 1;
$b = 10;
add($a);
echo "a is $a,";
add($b);
echo " a is $a, and b is $b"; // Note: $a and $b are NOT referenced
PPL
fonte
-7

Depende da versão, 4 é por valor, 5 é por referência.

Karl Seguin
fonte
11
Eu não acho que isso seja verdade.
31510 Nick Heiner
@Karl Seguin, é parcialmente verdade. Antes do objeto PHP5, por padrão, serem passados ​​por valor, mas desde 5 são passados ​​pelo manipulador, o que na prática pode ser tratado como uma referência (com algumas exceções), porque podemos modificar as propriedades do objeto através deles php.net/manual/en/language. oop5.references.php .
Adam Faryna 28/04