PHP变量是通过值传递还是通过引用传递?

PHP变量是按值传递还是按引用传递?

210947 次浏览

取决于版本,4是值,5是引用。

PHP变量按值赋值,按值传递给函数,当包含/表示对象时通过引用传递。您可以使用'&'强制变量通过引用传递。

由值/引用示例赋值:

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


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

输出:

Var1:测试,var2:最终测试,var3:最终测试

按值/引用示例传递:

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


changeThem($var1, $var2);


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


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

输出:

var1: foo, var2 BAR

引用示例传递的对象变量:

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";
}

输出:

喷火

(最后一个例子可能更好。)

它是根据PHP文档的值。

默认情况下,函数实参是按值传递的(这样,如果函数内实参的值改变了,它不会在函数外被改变)。为了允许函数修改其参数,它们必须通过引用传递。

要让函数的实参始终通过引用传递,请在函数定义中的实参名称前加上&号(,)。

<?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.'
?>

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

在PHP 5中有一个新的对象模型。PHP对对象的处理已经完全重写,允许更好的性能和更多的特性。在以前的PHP版本中,对象是像基本类型一样处理的(例如整数和字符串)。这种方法的缺点是,当变量被赋值或作为参数传递给方法时,从语义上复制整个对象。在新的方法中,对象是通过句柄引用的,而不是通过值引用的(可以把句柄看作对象的标识符)。

在PHP5中,包含基本类型的变量是按值传递的。包含对象的变量是通过引用传递的。2006年的Linux Journal上有一篇非常有趣的文章提到了4和5之间的OO差异。

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

似乎很多人都对对象传递给函数的方式和引用传递的含义感到困惑。对象仍然是按值传递的,只是PHP5中传递的值是引用句柄。证明:

<?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";

输出:

a, b

通过引用传递意味着我们可以修改调用者看到的变量,显然上面的代码没有做到这一点。我们需要将swap函数更改为:

<?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";

输出:

b, a

为了通过引用传递。

两种方法都可以。

在前面放一个'&'符号,你传递的变量就变成了它的原点,也就是说,你可以通过引用传递,而不是复制它。

所以

    $fred = 5;
$larry = & $fred;
$larry = 8;
echo $fred;//this will output 8, as larry and fred are now the same reference.
对象在PHP 5中通过引用传递,在PHP 4中通过值传递。 默认情况下,变量是按值传递的!< / p >

阅读这里:http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html

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>";

属性在没有通过引用传递时仍然是可以修改的,所以要小心。

输出:

SwapObjects: b, a SwapValues: a, b

在PHP中,默认情况下,对象作为新对象的引用传递。

请看这个例子:

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

现在看这个:

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.

现在看这个:

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.

我希望你能理解。

可以通过引用将变量传递给函数。这个函数将能够修改原始变量。

你可以在函数定义中通过引用来定义段落:

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


$result=5;
changeValue($result);


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

实际上这两种方法都是有效的,但这取决于你的需求。通过引用传递值通常会使脚本变慢。因此,考虑到执行时间,最好按值传递变量。此外,当按值传递变量时,代码流更加一致。

当您希望简单地更改原始变量并将其返回到相同的变量名并赋予其新值时,可以将此用于函数。

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

博士TL;: PHP同时支持按值传递和按引用传递。引用使用&号(&)声明;这与c++的做法非常相似。当函数的形参没有使用&号声明时(即,它不是引用),一切将按值传递,包括对象。对象和原语的传递没有区别。关键是要理解什么是在将对象传递给函数时传递的。这就是理解指针的价值所在。

对于将来遇到这种情况的任何人,我想分享这个来自PHP文档,由匿名用户发布的宝石:

这里似乎有些混乱。指针和引用之间的区别并不是特别有用。 行为中的一些“全面”;已经发布的例子可以用更简单的统一术语来解释。例如,Hayley的代码正在做您应该期望它应该做的事情。(使用>= 5.3)

< p >第一原则: 指针存储访问对象的内存地址。任何时候赋值一个对象,都会生成一个指针。(我还没有深入研究Zend引擎,但据我所知,这适用)

第二个原则,也是最混乱的来源: 将变量传递给函数默认情况下是作为值传递完成的,即,您正在处理一个副本。但是对象是通过引用传递的!这是这里和Java世界中常见的误解。我从来没说过什么。默认的传递是按值进行的。总是这样。然而,被复制和传递的是指针。当使用"->"时,您当然将访问与调用函数中的原始变量相同的内部变量。只是使用"="

< p >三原则: “,“自动且永久地将另一个变量名/指针设置为与其他变量相同的内存地址,直到将它们解耦。使用术语“别名”是正确的。在这里。把它想象成在臀部连接两个指针,直到用“unset()”强行分开。此功能既存在于同一作用域中,也存在于将参数传递给函数时。通常传递的参数被称为“引用”,“引用”;由于“价值传递”与“价值传递”之间的某些区别;而“参照传递”;在C和c++中更清晰。

只要记住:传递给函数的是指向对象的指针,而不是对象本身。这些指针都是原始指针的副本,除非你使用"& "在参数列表中传递原始值。只有当你深入到一个物体的内部时,原始的东西才会改变。

下面是他们提供的例子:

<?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.
}


?>

我写了一篇关于JavaScript主题的广泛而详细的博客文章,但我相信它同样适用于PHP、c++和任何其他人们似乎对按值传递和按引用传递感到困惑的语言。

显然,PHP与c++一样,是一种支持引用传递的语言。默认情况下,对象是按值传递的。在使用存储对象的变量时,将这些变量视为指针会有所帮助(因为在程序集级别上,这就是它们的本质)。如果你按值传递指针,你仍然可以“跟踪”;指针,并修改所指向对象的属性。你不能做的是让它指向另一个对象。只有当您显式地将参数声明为通过引用传递时,才能够这样做。

关于如何将对象传递给函数,你仍然需要理解没有"&",你传递给函数一个对象句柄,对象句柄仍然是通过值传递的,它包含一个指针的值。但是你不能改变这个指针,除非你通过引用传递它,使用" "

<?php
class Example
{
public $value;
         

}
        

function test1($x)
{
//let's say $x is 0x34313131
$x->value = 1;  //will reflect outsite of this function
//php use pointer 0x34313131 and search for the
//address of 'value' and change it to 1


}
        

function test2($x)
{
//$x is 0x34313131
$x = new Example;
//now $x is 0x88888888
//this will NOT reflect outside of this function
//you need to rewrite it as "test2(&$x)"
$x->value = 1000; //this is 1000 JUST inside this function
                 

        

}
         

$example = new Example;
    

$example->value = 0;
    

test1($example); // $example->value changed to  1
    

test2($example); // $example did NOT changed to a new object
// $example->value is still 1
     

?>

PHP引用是一个别名,允许两个不同的变量写入相同的值。

在PHP中,如果你有一个包含对象的变量,这个变量不包含对象本身。相反,它包含该对象的标识符。对象访问器将使用标识符查找实际对象。因此,当我们在函数中使用对象作为参数或将其赋值给另一个变量时,我们将复制指向对象本身的标识符。

https://hsalem.com/posts/you-think-you-know-php.html

class Type {}


$x = new Type();
$y = $x;
$y = "New value";


var_dump($x); // Will print the object.
var_dump($y); // Will print the "New value"


$z = &$x; // $z is a reference of $x


$z = "New value";
var_dump($x); // Will print "New value"
var_dump($z); // Will print "New value"