【问题标题】:PHP function array parameter by referencePHP函数数组参数通过引用
【发布时间】:2013-01-14 20:27:54
【问题描述】:

为什么这段代码不能像我预期的那样工作? 在 Test(&$array) 函数中,我将 ref 参数设置为全局 $array1 但这不起作用。

$array1 = array();
$array2 = array();

function Test(&$array)
{
    global    $array1;
    $array = &$array1;

    $array['inside'] = 'inside';

}

//按功能设置:

Test($array2); 
$array2['test1'] = 'test1';

var_dump($array1); //array('inside' => 'inside') ** WHERE IS THE 'test1'  key? **
var_dump($array2); //array('test1' => 'test1')   ** WHERE IS THE 'inside' key? **

//设置不带函数:

$array2 = &$array1;
$array2['test2'] = 'test2';

var_dump($array1); //array('inside' => 'inside', 'test2' => 'test2') ** FINE **
var_dump($array2); //array('inside' => 'inside', 'test2' => 'test2') ** FINE **

编辑:

很明显,如果我将 $array 更改为指向 $array1 那么 $array1 将具有 'inside' => 'inside' 值 outside 函数。如果我设置 $array2['test1'] = 'test1' 为什么不改变这个 $array1,有什么不清楚的地方?它在函数内部之前“链接”!

【问题讨论】:

  • 听说过返回值吗?
  • @kingcrunch 这显然是一个简化的测试用例,因此批评一个未知的用例似乎没有什么帮助。
  • @IMSoP 好的,抱歉 :) 但老实说:多年来我从未见过有用的 in-out-params 用例,我担心它们根本不存在(不再存在) )。但是我已经看到了微优化的传递引用(此外:它没有优化任何东西,因为写时复制)然后相同的开发人员感到困惑,因为数组“神奇地”改变了,因为其他一些使用数组,比如一个使用数组,作为参数传递:) 我想说的是:没有真正的用例,但许多“wtf”-momemts 正在等待。
  • @KingCrunch:真正的函数应该返回布尔值,同时通过引用设置多个参数值。这是我的 .NET C# 解决方案中的一种设计模式。我就是喜欢用php来实现。
  • @ggabor 这种“返回值作为状态参数”是一个坏习惯。当你的方法失败时,使用异常,当它成功时,......好吧,不要抛出异常;)然后继续。这就是异常存在的原因:通知您(并让您有机会对)异常情况做出反应。公平地说:也许在其他语言中它是一种更被采用的模式,但至少在我所知道的语言中不是:)(我对 C 系列不太熟悉)

标签: php arrays function reference


【解决方案1】:

当您在函数中执行$array = &$array1; 时,您正在更改局部变量$array 的值。

它曾经引用$array2,但现在它包含对$array1 的引用。所以当你修改$array时,你就是在修改$array1

【讨论】:

  • @IMSoP:& 表示“引用”,因此=& 表示该变量拥有指向另一个变量的“链接”。
  • 所以这意味着我不能修改函数之外的任何参数值,即使它是通过引用传递的。每个函数参数都是只读的,即使通过引用传递?
  • @ggabor:问题是您更改了引用指向的位置。 $array 曾经指向 $array2,但您将其更改为指向 $array1,所以这就是被修改的数组。如果您没有$array = &$array1; 行,那么$array['inside'] = 'inside'; 将修改$array2
  • @RocketHazmat 这正是我(我相信其他人)犯的错误:它不是对另一个变量的引用,两个变量都是对相同值的引用.在任一变量上再次使用=&,它们将被取消链接。
【解决方案2】:

这是我对 PHP 中的引用的理解,以及为什么该代码没有达到您的预期(如果我弄错了,请有人跳到我这里,我经常使用引用!另外,我相信还有更好的术语而不是我所说的“标识符”和“价值”;我只是想避免在这两个概念中使用“变量”。)

  • 有一堆变量标识符(获取数据的方式)和一堆变量值(数据实际在哪里)
  • 对于普通变量,只有一个标识符指向一个值。例如$foo 指的是一个特定的值——PHP 内部某个地方的一个桶,可以保存一个数字、一个字符串等
  • 每次使用普通赋值运算符时,例如$foo = 42,PHP 查找指向的值并对其进行更新 - 因此标识符 $foo 没有改变,但它指向的值已经改变。
  • 当您分配参考时,例如$bar =& $foo,您实际上是在告诉 PHP 更改标识符本身。所以现在$bar$foo 是指向相同值的两个不同标识符。 $foo = -1$bar = -2 都会写入这个值,无论你给它起什么名字,你指的是那个值。
  • 到目前为止,一切都很好。但是如果我现在写$foo =& $bob 会怎样?由于我更改的是标识符,而不是$foo 开始指向与$bob 相同的值,但$bar 保持原样。所以现在,更改 $foo 不会再对 $bar 产生任何影响。
  • 当您通过引用函数传入参数时,也会发生类似的情况。所以在问题的例子中,Test($array2) 行仍然在名为$array 的函数内创建了一个新的标识符,但它指向与@ 相同的 987654337@。但是,函数内部是行$array = &$array1,它采用新标识符($array)并将其指向与$array1 相同的值。 $array2 仍然指向的旧值没有改变。
  • 还有其他类似的情况。例如,globalstatic 关键字创建了一个额外的标识符,指向一个现有的值。如果你写function foo() { global $foo; $bar = 2; $foo =& $bar; },只有函数的本地标识符$foo被更新为指向$bar的值;全局标识符(当您在全局范围内时,它恰好也称为 $foo)仍指向其原始值。

PHP 中普通值的引用系统总是包含精确的一级间接 - 例如,您不能像在 C 中那样创建指向指针的指针。

唯一棘手的情况是对象,因为在许多语言中,对象都有自己的额外间接级别 - 而$foo = 42; $bar = $foo; 将表示42 的数据从$foo 的值复制到$bar 的值, $foo = new stdClass; $bar = $foo 复制一个对象指针。所以尽管$foo$bar 仍然有单独的,像$foo = 42 这样的赋值不会对$bar$foo->a = 1;$bar->a = 1 产生任何影响。改变同一个对象。

【讨论】:

  • 是的,这听起来不错。这就是我试图解释的:-P
  • @RocketHazmat 或许可以用来总结总结——我不太擅长简洁... ;)
猜你喜欢
  • 2012-05-16
  • 2011-12-15
  • 1970-01-01
  • 2011-02-06
  • 2020-11-29
  • 1970-01-01
  • 1970-01-01
  • 2016-01-04
  • 1970-01-01
相关资源
最近更新 更多