As variáveis do PHP são passadas por valor ou por referência?
As variáveis do PHP são passadas por valor ou por referência?
Respostas:
É 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.'
?>
$str = add_some_extra($str);
se eu não estivesse usando a referência, certo? então qual é o verdadeiro valor agregado disso?
$str
seria atribuída nula, no seu caso.
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.
$y
não é necessário - não há nada function changeValue
que exija que ele esteja dentro class Y
, para que emaranhe dois conceitos não relacionados. Eu mudaria function changeValue
para 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 type
de $x
- o fato de que tanto X
e Y
acontecer para incluir um $abc
campo também é irrelevante para o que é demonstrado
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.
swap
funçã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.
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).
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 ...)
$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 &
.
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
?>
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.
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.
&
.
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
&
.
&
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.
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
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.
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.
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 & 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
Depende da versão, 4 é por valor, 5 é por referência.