PHP变量是按值传递还是引用传递?
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.'
?>
$str = add_some_extra($str);
相同,对吗?那么这样做的真正附加值是什么? - Obmerk Kronenclass 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.
我希望你能理解这个。
$y
是不必要的 - function changeValue
中没有任何需要它在 class Y
内部的东西,因此将两个不相关的概念缠绕在一起。我会将 function changeValue
移动到外部作用域,就在 $x = new X();
的上面。删除所有对 $y
的引用。现在更容易看出前两个示例保持 $x 不变,第三个示例将其内容更改为 new Y()
。如果您转储了 $x
的 type
,则更容易看到这一点 - X
和 Y
都包括 $abc
字段的事实也与所展示的内容无关。 - ToolmakerSteve看起来很多人对于对象在函数中的传递及按引用传递的概念感到困惑。实际上,对象仍然是按值传递的,在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
$object->foo = 1;
将被调用者看到。在你的例子中,你正在为该名称分配一个新引用,这将擦除旧引用。这并不会使它更少成为引用。 - DimeCadmium&$foo
更合适地被称为别名或绑定。 “按值传递”和“按引用传递”(以及实际上“引用”)在PHP范围之外已经具有现有的意义,而PHP奇怪的定义与其根本不兼容。 - DimeCadmiumPHP变量通过值赋值,通过值传递给函数,当包含/表示对象时,则通过引用传递。您可以使用'&'强制变量通过引用传递。
按值/引用赋值示例:
$var1 = "test";
$var2 = $var1;
$var2 = "new test";
$var3 = &$var2;
$var3 = "final test";
print ("var1: $var1, var2: $var2, var3: $var3);
输出:
变量1:测试,变量2:最终测试,变量3:最终测试
按值/引用传递示例:
$var1 = "foo";
$var2 = "bar";
changeThem($var1, $var2);
print "var1: $var1, var2: $var2";
function changeThem($var1, &$var2){
$var1 = "FOO";
$var2 = "BAR";
}
输出:
变量1: foo, 变量2: 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";
}
输出:
FOO
(最后一个示例可能还有改善空间。)
$foo
的值是指向一个对象的指针。在函数 changeFoo()
中,由于未使用 &
声明其参数,因此 $foo
被按值传递。 - newacct你可以通过引用将变量传递给函数。这个函数将能够修改原始变量。
您可以在函数定义中通过引用定义传递的参数:
<?php
function changeValue(&$var)
{
$var++;
}
$result=5;
changeValue($result);
echo $result; // $result is 6 here
?>
&
)声明引用,这与C ++非常相似。当函数的形式参数未使用&符号声明时(即它不是一个引用),所有内容都是按值传递的,包括对象。对象和基元素的传递方式没有区别。关键是要理解在将对象传递到函数中时会传递什么。这就是理解指针的价值所在。
对于将来遇到此问题的任何人,我想分享PHP文档中匿名用户发布的信息中的宝石:
这里似乎存在一些混淆。指针和引用之间的区别并没有特别有帮助。一些“全面”的示例中的行为可以用更简单的统一术语来解释。例如,Hayley的代码正在做您应该期望它应该做的事情。(使用 >= 5.3)
第一个原则: 指针存储内存地址以访问对象。每次分配对象时,都会生成一个指针。(我还没有深入研究Zend引擎,但据我所见,这适用于所有情况)
第三原则: "&" 会自动且永久地将另一个变量名/指针设置为与其他东西相同的内存地址,直到你解除它们之间的关系。在这里使用术语“别名”是正确的。可以将其视为将两个指针连接在一起,直到通过 "unset()" 强制分离。这种功能存在于相同的作用域和传递给函数参数时。通常传递的参数称为“引用”,因为在 C 和 C++ 中“按值传递”和“按引用传递”之间的某些区别更清晰。第二个原则,也是最容易混淆的来源: 默认情况下,将变量传递给函数作为值传递,即您正在使用副本。 "但是对象是按引用传递的!" 这是这里和Java世界中的一种常见误解。我从未说过复制了什么。默认传递是按值进行的。总是。然而,被复制并传递的是指针。当使用“->”时,您当然将访问调用函数中原始变量的相同内部。只使用“=”将仅使用副本。
<?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++一样支持按引用传递。默认情况下,对象是按值传递的。在处理存储对象的变量时,将这些变量视为指针会有所帮助(因为从汇编级别来看,这就是它们的本质)。如果您通过值传递一个指针,仍然可以“跟踪”该指针并修改所指向的对象的属性。您不能做的是让它指向另一个对象。只有明确声明参数按引用传递,您才能够这样做。
$fred = 5;
$larry = & $fred;
$larry = 8;
echo $fred;//this will output 8, as larry and fred are now the same reference.
在PHP5中,包含原始类型的变量按值传递。包含对象的变量按引用传递。 2006年,《Linux Journal》发表了一篇非常有趣的文章,提到了这一点以及4和5之间的其他面向对象差异。
&
,则在 PHP 中所有变量都是按值传递的。 - newacctclass 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