【问题标题】:Empty array after passing array by reference to array_walk()通过引用 array_walk() 传递数组后的空数组
【发布时间】:2013-06-14 18:34:40
【问题描述】:

我做了这个小班:

class Analyzer {
    public static function analyze($phrases) {
        $sortedPhrases = array();
        array_walk($phrases, array('self', 'splitByLength'), $sortedPhrases);
        var_dump($sortedPhrases);
    }

    private static function splitByLength($item, $key, &$resArr) {
        // line stolen from here: http://stackoverflow.com/a/4786840/603003
        // thanks to arnaud576875 <http://stackoverflow.com/users/576875/arnaud576875>
        $len = count( preg_split('#\PL+#u', $item, -1, PREG_SPLIT_NO_EMPTY) );
        if (!isset($resArr[$len])) {
            $resArr[$len] = array();
        }
        $resArr[$len][] = $item;

        var_dump($resArr);
    }
}

$phrases = array(
    "I can't believe the great content",
    "I can't understand the superior information",
    "I can't comprehend the amazing data",
    "I cannot analyze the amazing data",
    "I haven't written to the amazing data"
);
Analyzer::analyze($phrases);

执行脚本会产生以下输出:

array (size=1)
  7 => 
    array (size=1)
      0 => string 'I can't believe the great content' (length=33)

...

array (size=3)
  7 => 
    array (size=3)
      0 => string 'I can't believe the great content' (length=33)
      1 => string 'I can't understand the superior information' (length=43)
      2 => string 'I can't comprehend the amazing data' (length=35)
  6 => 
    array (size=1)
      0 => string 'I cannot analyze the amazing data' (length=33)
  8 => 
    array (size=1)
      0 => string 'I haven't written to the amazing data' (length=37)

array (size=0)
  empty

所有输出实际上都是正确的,除了来自 Analyzer::analyze() 的最后一个输出。似乎变量$sortedPhrasesarray_walk() 之后被清除了。

【问题讨论】:

  • 公开您的私有函数并在特定数据上对其进行测试,如果它有效,您一定不能将正确的值传递给您的回调
  • @MichaelSole 我在课堂外使用 splitByLength 时得到相同的效果。

标签: php arrays reference traversal


【解决方案1】:

好好看看array_walk's documentation page

用户数据

如果提供了可选的 userdata 参数,它将作为 回调函数名的第三个参数。

这是第三个参数。它不是一个引用,它只是一个传递给你的回调函数的值。


您的问题的一个(众多)解决方案是使用一个对象来代替(对象总是通过引用传递):

class Analyzer {
    public static function analyze($phrases) {
        $arrObj = new ArrayObject();
        array_walk($phrases, array('self', 'splitByLength'), $arrObj);
        var_dump($arrObj->getArrayCopy());
    }

    private static function splitByLength($item, $key, $arrObj) {
        // line stolen from here: http://stackoverflow.com/a/4786840/603003
        // thanks to arnaud576875 <http://stackoverflow.com/users/576875/arnaud576875>
        $len = count( preg_split('#\PL+#u', $item, -1, PREG_SPLIT_NO_EMPTY) );
        if (!isset($arrObj[$len])) {
            $arrObj[$len] = array();
        }
        $arrObj[$len][] = $item;

        var_dump($arrObj->getArrayCopy());
    }
}

(不一定是ArrayObject,可以是带有数组属性的stdClass对象,也可以根据需要创建自己的类...)


如果您真的想使用引用,也可以将调用包装在匿名函数中:

$static = get_called_class();
array_walk($phrases, function($item, $key) use($static, &$sortedPhrases){
  $static::splitByLength($item, $key, $sortedPhrases);
});

【讨论】:

  • 脱帽致敬!我正在摆弄代码并得出结论:传递给 map 函数的额外参数不能是引用。不知道ArrayObject,很有趣。另一种可能的解决方案是使用静态成员变量,但 ArrayObject 解决方案要简单得多。
  • 谢谢,现在可以完美运行了!但我仍然在问自己,为什么普通数组在 遍历 数组时不会失去它的价值。对回调函数的最后一次调用实际上转储(全部正确)收集的值。我认为它必须与内部实现有关。 (您将在 23 小时内获得赏金;)。
  • 因为普通数组是第一个参数,它是一个引用(注意&amp;文档中的描述)
【解决方案2】:

虽然发送给回调函数的第三个参数本身不能是引用,但它可以包含引用。

另一种方法(使用对象或将回调包装在闭包中)是将数组传递给回调,其中包含对要更新的变量的引用。包装数组按值传递,但它包含的只是您要更改的引用值。

class Analyzer {
    public static function analyze($phrases) {
        // …
        array_walk($phrases,
                   array('self', 'splitByLength'),
                   array(&$sortedPhrases));
        // …
    }

    private static function splitByLength($item, $key, $extra_args) {
        $resArr = &$extra_args[0];
        // …
    }
}

【讨论】:

  • 感谢您提供另一个不错的解决方案!
【解决方案3】:

很确定这是错误的:

array_walk($phrases, array('self', 'splitByLength'), $sortedPhrases);

所以,试试这个:

$sortedPhrases = array_walk($phrases, 'splitByLength');

并在$sortedPhrases 中返回您的值,并且不要使用传递引用(个人事情)

【讨论】:

  • PHP 产生 array_walk() expects parameter 2 to be a valid callback,因为这当然不是一个有效的回调。
猜你喜欢
  • 2011-08-09
  • 1970-01-01
  • 2011-12-15
  • 2020-07-30
  • 2012-04-17
  • 2014-08-06
  • 2020-03-09
  • 2019-06-29
相关资源
最近更新 更多