【问题标题】:PHP modifying array elements by referencePHP通过引用修改数组元素
【发布时间】:2012-09-10 10:30:10
【问题描述】:

我有一个正在检查内容的大型数据集;我在创建数据的内部数组时进行此验证;为避免以后再次循环数组,我希望验证更改数组的内容。 现在的问题是我正在通过 call_user_func 调用验证例程,这似乎给通过引用带来了一些问题。或者我做错了什么。

这是一个精简的例子:

public function index( )
{
    $arr = array( 
        array('a' => 'aap', 'n' => 'noot', 'm' => 'mies'), 
        array('a' => 'ding', 'b' => 'flof', 'c' => 'bips'), 
        array( 'd' => 'do', 'e' => 're', 'c' => 'mi') 
    );

    $func = array( $this, '_user_func' );

    $errors = 0;
    $new_arr = array();
    foreach ($arr as $key => &$value) {
        $new_arr[$key] = &$value; // Simulate production-code manipulation
        //if ( !$this->_do_callback($func, $new_arr[$key], $key) ) $errors++; // No exception but array not modified afterwards
        if ( !call_user_func( $func, $new_arr[$key], $key ) ) $errors++; // Exception: Parameter 1 to TestRef::user_func() expected to be a reference, value given
    }
    unset($value);
    var_dump($new_arr);
    print_r('Errors: '.$errors);
}

private function _do_callback( $func, array &$row, $row_id )
{
    if ( is_callable( $func ) )
    {
        return call_user_func( $func, $row, $row_id );
    }
    else
    {
        throw new Exception( "Error doing callback. Callback empty or not a callable function." );
    }
}

private function _user_func( &$arr, $index = 0 )
{
    // "Validation" routine
    foreach ($arr as $key => &$value) {
        if ($key == 'b') return FALSE; // Simulate validation error for error count
        $arr[$key] = 'replaced';
    }
    unset($value);
    //var_dump($arr); // Works!
    return TRUE;
}

【问题讨论】:

    标签: php arrays byref


    【解决方案1】:

    我认为您正在尝试重新定义现有的 php 函数,即 array_walk。 特别是在你的情况下,你需要array_walk_recursive

    这是您的代码的重写(简化?)版本。

        public function index( )
        {
            $arr = array( 
                array('a' => 'aap', 'n' => 'noot', 'm' => 'mies'), 
                array('a' => 'ding', 'b' => 'flof', 'c' => 'bips'), 
                array( 'd' => 'do', 'e' => 're', 'c' => 'mi') 
            );
    
            $func = array( $this, '_user_func' );
    
            var_dump($arr); // BEFORE WALK
            array_walk_recursive($arr, $func);
            var_dump($arr); // AFTER WALK
        }
    
        /**
         *  Does something to a row from an array (notice the reference)
         */
        private function _user_func( &$rowValue, $rowIndex )
        {
                $rowValue = 'replaced';
        }
    

    你可以在这里看到这段代码 --> http://ideone.com/LcZKo

    【讨论】:

    • 不错!我什至以同样的方式构想了索引部分.. :) 对于我的情况,我认为 array_walk 会更合适(而不是递归),因为我对每一行进行操作,而不是对每一行的每个值进行操作。我看看能不能把它翻译成真正的应用程序。
    • 这个问题在于,在生产代码中,很多事情发生在外部循环中,甚至在使用 $row 进行回调之前。 array_walk 只有在收集 $arr 之后才有可能。但这意味着再次迭代整个集合,这是我试图避免的。确实如此:我正在尝试重写 array_walk,排序:) PHP 人员如何进行回调?
    • 另外,如果回调失败,我只想计算错误并继续下一行。我想如果我现在在被调用者中返回 false,整个 array_walk 会停止吗?
    • 回调 --> stackoverflow.com/questions/48947/… 顺便说一句,我还不清楚某些方面:-“如果回调失败”:“失败”是什么意思? (错误,异常,...)?失败从何而来?谁/什么提出了它? - “如果我在被调用者中返回 fals”:因为您正在使用引用,所以您没有返回值?你在哪里/如何得到它们?如您所见,您最好改写您的问题或详细说明恕我直言。
    • 我真的不明白“use”关键字在这里有什么帮助(这并不意味着它没用)。根据您之前所说的,我知道只要满足某些条件,您就需要对某些数组元素运行一些代码。因此 array_walk 不太适合,因为您无法退出“步行”。这是一个尝试做你似乎正在寻找的东西-->ideone.com/41gmQ也许你可以编辑这个尝试以满足你的需要,从而澄清你真正需要的东西。
    【解决方案2】:

    任一

    尝试将您的 foreach 循环更改为:

    foreach ($arr as $key => &$value) {
        $this->_do_callback($func, $value, $key); // No exception but array not modified afterwards
        //call_user_func( $func, $value, $key ); // Exception: Parameter 1 to TestRef::user_func() expected to be a reference, value given
    }
    
    unset($value); // avoid memory leak
    

    在调用 call_user_func 之前将变量包装在一个数组中。

    【讨论】:

    • 我尝试了你的第一个建议;这是隐藏直接调用 call_user_func 引发的异常的另一种方法;但结果数组仍然具有原始值。
    • 将变量包装在数组中会做什么? (按照您的建议盲目地做不会产生任何结果:))
    • 它正确地保留了指针。对不起,乱七八糟,但我认为应该这样做:pastebin.com/VnKNKZGD
    • 嗯,很有趣。但它仍然会抛出“TestRef::_user_func() 的参数 1 应为参考,给定值”
    • 将它直接传递给函数 does 似乎有效: call_user_func( $func, array(&$value), $key );不得不做 "$arr = &$arr[0];" 有点烦人不过,现在在被调用者的开头..
    【解决方案3】:

    你试过这样吗:?

    foreach ($arr as $key => &$value) {
            $this->_do_callback($func, $value, $key); // No exception but array not modified afterwards
            //call_user_func( $func, $value, $key ); // Exception: Parameter 1 to TestRef::user_func() expected to be a reference, value given
        }
    

    【讨论】:

    • 是的,这是另一种隐藏直接调用 call_user_func 抛出的异常的方法;但结果数组仍然具有原始值。
    猜你喜欢
    • 1970-01-01
    • 2012-06-04
    • 1970-01-01
    • 2021-10-14
    • 2016-04-02
    • 1970-01-01
    • 2017-05-04
    • 1970-01-01
    • 2013-10-21
    相关资源
    最近更新 更多