【问题标题】:Passing/Returning references to object + changing object is not working传递/返回对对象的引用+更改对象不起作用
【发布时间】:2015-12-18 14:02:21
【问题描述】:

我正在使用How to get random value out of an array 中的an answer 编写一个从数组中返回随机项的函数。我将其修改为pass by referencereturn a reference

不幸的是,它似乎不起作用。对返回对象的任何修改都不会持续存在。我做错了什么?

如果有什么不同,我正在使用 PHP 5.4(不要问)。

function &random_value(&$array, $default=null)
{
    $k = mt_rand(0, count($array) - 1);
    $return = isset($array[$k])? $array[$k]: $default;
    return $return;
}

用法...

$companies = array();
$companies[] = array("name" => "Acme Co",  "employees"=> array( "John", "Jane" ));
$companies[] = array("name" => "Inotech",  "employees"=> array( "Bill", "Michael" ));

$x = &random_value($companies);
$x["employees"][] = "Donald";
var_dump($companies);

输出...

array(2) {
  [0] =>
  array(2) {
    'name' =>
    string(7) "Acme Co"
    'employees' =>
    array(2) {
      [0] =>
      string(4) "John"
      [1] =>
      string(4) "Jane"
    }
  }
  [1] =>
  array(2) {
    'name' =>
    string(7) "Inotech"
    'employees' =>
    array(2) {
      [0] =>
      string(4) "Bill"
      [1] =>
      string(7) "Michael"
    }
  }
}

我什至从文档中复制并粘贴了示例,但这些示例都不起作用。他们都输出null

【问题讨论】:

  • 客户需求!我只能以多种方式多次告诉他们,使用 5.4 是一个糟糕的主意。
  • 我知道,你说不要问,所以我当然不得不问。
  • 可能客户会回复scary graphs
  • 你为什么使用引用?你只是想从$companies返回一个随机数组吗?
  • @bishop 需要更多红色!我实际上向他们展示了这一点,他们还没有改变主意。

标签: php pass-by-reference


【解决方案1】:

三元运算符创建了一个隐式副本,它破坏了引用链。使用明确的if... else

function &random_value(&$array, $default=null)
{
    $k = mt_rand(0, count($array) - 1);
    if (isset($array[$k])) {
        return $array[$k];
    } else {
        return $default;
    }
}

至于为什么,docs 现在状态:

注意:请注意,三元运算符是一个表达式,它的计算结果不是变量,而是表达式的结果。了解是否要通过引用返回变量很重要。语句 return $var == 42 ? $a : $b;因此,在按引用返回的函数中将不起作用,并且在以后的 PHP 版本中会发出警告。

另请参阅this bug,其中三元运算符实际上在 foreach 上下文中通过引用返回,而实际上它不应该返回。

【讨论】:

  • 我刚试过。我返回同样的错误结果。
  • 它也适用于我!我将不得不阅读为什么三元运算符会这样做。我不希望会发生这种情况(显然!)。谢谢!
  • 嗯。您的函数仍然返回整个数组。他只想要一个元素不是吗?
  • 这就是 zval 写时复制处理在引擎中发生的方式,至少在 5.6 之前是这样。另见this post。我不确定如果在 7 中发生任何变化会怎样。(我对此表示怀疑。)
  • @Jaime: 只为我和3v4l 返回一个元素。请注意,每个元素都是由两个键组成的数组:nameemployees
【解决方案2】:

由于我刚刚吃了一顿丰盛的午餐,所以我很难找到比 @bishop 更好的功能方面,但这很有效:

$x =& $companies[array_rand($companies)];
$x["employees"][] = "Donald";
var_dump($companies);

【讨论】:

  • 我也会推荐这种方法,但我认为缓解因素是将$default 用于空值,例如:$companies = [ [], ['name' => 'Foo', 'employees' => []] ];
猜你喜欢
  • 1970-01-01
  • 2011-08-15
  • 2020-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-06
相关资源
最近更新 更多