Php 传递引用不使用数组_walk _recursive的其他参数,除非它';s不推荐使用的调用时间按引用传递

Php 传递引用不使用数组_walk _recursive的其他参数,除非它';s不推荐使用的调用时间按引用传递,php,pass-by-reference,Php,Pass By Reference,一段时间以来,我一直在使用“传统”递归函数来展平多维数组,例如 $baseArray = array(array('alpha'), array('beta','gamma'), array(), array(array('delta','epsilon'), array('zeta',array('eta',

一段时间以来,我一直在使用“传统”递归函数来展平多维数组,例如

$baseArray = array(array('alpha'),
                   array('beta','gamma'),
                   array(),
                   array(array('delta','epsilon'),
                         array('zeta',array('eta',
                                            'theta'
                                           ),
                              ),
                        ),
                   array('iota'),
                  );
到一个简单的一维数组

昨天晚上,我想我应该看看如何使用它,看看是否可以使它更高效、更清洁

我的第一次尝试不是很成功:

function flattenArray($arrayValue, $arrayKey, &$flatArray) {
    $flatArray[] = $arrayValue;
}


$flattenedArray = array();
array_walk_recursive($baseArray,'flattenArray',$flattenedArray);
我认为它应该会起作用,但我得到的只是一系列错误:

Warning: Cannot use a scalar value as an array in C:\xampp\htdocs\arrayTest.php on line 16
结果是:

array(0) { }
函数中的类型暗示给了我

Catchable fatal error: Argument 3 passed to flattenArray() must be an array, integer given in C:\xampp\htdocs\arrayTest.php on line 16
使用闭包可以得到相同的结果

我能让它工作的唯一方法(无需为我的FlattedArray使用全局或静态)是使用调用时间传递引用:

function flattenArray($arrayValue, $arrayKey, $flatArray) {
    $flatArray[] = $arrayValue;
}


$flattenedArray = array();
array_walk_recursive($baseArray,'flattenArray',&$flattenedArray);
这会产生正确的结果

array(9) { [0]=> string(5) "alpha" [1]=> string(4) "beta" [2]=> string(5) "gamma" [3]=> string(5) "delta" [4]=> string(7) "epsilon" [5]=> string(4) "zeta" [6]=> string(3) "eta" [7]=> string(5) "theta" [8]=> string(4) "iota" }
但给了我一个不意外的警告

Deprecated: Call-time pass-by-reference has been deprecated in C:\xampp\htdocs\arrayTest.php on line 22
我知道PHP是一种古怪的语言,但这似乎有点极端。文档清楚地显示了array_walk_recursive的第一个参数是按引用传递的,但似乎其他参数只能在调用时按引用传递。奇怪

PHP版本是5.3.8

关于如何使用array\u walk\u recursive正确展平我的数组,而不会出现不推荐的错误(除了提交错误报告之外)的任何建议

编辑

附言

我知道我可以使用闭包绕过此问题:

$flattenedArray = array();
array_walk_recursive($baseArray, function($arrayValue, $arrayKey) use(&$flattenedArray){ $flattenedArray[] = $arrayValue; } );
var_dump($flattenedArray);

但是,由于这是当前允许与PHP5.2.0一起使用的库所必需的,因此使用一个需要更高版本的PHP的特性在现阶段不是一个实用的选择,该特性在这一阶段没有特别的帮助

通过阅读PHP文档,我发现它对参数参数的描述有一个注释:

请注意,call_user_func()的参数不是通过 参考资料

但没有这样的通知

这可能纯粹是一个文档问题。。。如果我在array\u walk\u recursive()文档中看到类似的通知,我可能不会尝试(尽管好奇的人可能会不顾一切地尝试,只是为了看看发生了什么)


但是,我不明白为什么这两种情况都不应该接受回调函数定义中的传递引用参数。这确实让人感觉有点倒退。。。。如果不依赖于该不推荐使用的功能,确实有效的语言功能(尽管使用调用时间按引用传递)将不再有效。

不推荐使用调用时间按引用传递:

在array\u walk\u递归文档中没有注意到这一点,因为它不是特定于该函数的

您可以做的一件事是将对象和方法名(而不是函数名)作为回调传递,并将展开数组的状态作为该对象的成员进行维护

e、 g


可以这样想:您通过值将
$flatArray
传递到
array\u walk\u recursive
array\u walk\u recursive
将进一步通过引用将参数传递给函数。但当它通过值传递给
array\u walk\u recursive
时,引用将已经指向不同的值

我知道,这似乎是一个奇怪的限制,但当你考虑它的时候,它也是很合乎逻辑的

顺便说一句,我想你无意中还发现了另一个问题,它实际上看起来像是严重的内存损坏(看看打印的数组的第三个元素)。我会调查的

另一方面,平坦化的简单方法是使用递归ArrayIterator:

$flattenedArray = array();
foreach (new RecursiveIteratorIterator(
             new RecursiveArrayIterator($baseArray),
             RecursiveIteratorIterator::LEAVES_ONLY
         ) as $value) {
    $flattenedArray[] = $value;
}

由于您的解决方案是特定于版本的(根据文档,PHP5.2不应该抱怨调用时间),一个选项是创建包含每个实现的不同脚本,然后让另一个脚本有条件地包含定义展平函数的脚本(以及任何其他特定于版本的代码)取决于PHP版本

if (! defined('PHP_VERSION_ID')) {
    $version = explode('.', PHP_VERSION);
    define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
    if (PHP_VERSION_ID < 50207) {
        define('PHP_MAJOR_VERSION',   $version[0]);
        define('PHP_MINOR_VERSION',   $version[1]);
        define('PHP_RELEASE_VERSION', $version[2]);
    }
}
if (PHP_VERSION_ID < 50300) {
    include_once('php-5.2-.php');
} else {
    include_once('php-5.3+.php');
}
if(!defined('PHP\u VERSION\u ID')){
$version=explode('.',PHP_版本);
定义('PHP_VERSION_ID',($VERSION[0]*10000+$VERSION[1]*100+$VERSION[2]);
如果(PHP_版本_ID<50207){
定义('PHP_MAJOR_VERSION',$VERSION[0]);
定义('PHP_MINOR_VERSION',$VERSION[1]);
定义('PHP_RELEASE_VERSION',$VERSION[2]);
}
}
如果(PHP_版本_ID<50300){
包括_once('php-5.2-.php');
}否则{
包括_once('php-5.3+.php');
}

我知道不推荐使用调用时间传递引用,但我尝试的是一种直接的传递引用,它不推荐使用,但在回调函数中用于其他参数时似乎不起作用。我可能必须使用类属性作为回退方法。。。。这将在一个类中使用,一旦我可以让它工作。。。但我需要确保每当我使用展平方法时,我都会初始化属性,这是额外的,我可以看到逻辑,尽管我不确定我是否同意它。。。arrayValue参数通过引用传递给回调函数,允许更改数组值-函数转换器(&$arrayValue,$arrayKey){$arrayValue.='TEST';}数组_walk_recursive($baseArray,'changer');var_dump($baseArray);不过,内存损坏问题确实给我留下了潜在的严重印象。。。。在您突出显示它之前,我还没有看到任何证据。我当然认为应该有一些正式的说明,表明call\u user\u func()不能与回调函数中的其他参数一起使用,而不仅仅是我可能会给出的任何注释add@MarkBaker是的,我也担心腐败。这些数字看起来像指针,如果您使用它(通过在var_转储之前添加额外代码),您可以更改模式。我将ping#php.pecl,看看他们怎么说。@MarkBaker我一有时间就会加上这个注释;)我必须看看它是如何工作的,这不是一个特别干净的解决方案,但它可能会给我带来一些好处
if (! defined('PHP_VERSION_ID')) {
    $version = explode('.', PHP_VERSION);
    define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
    if (PHP_VERSION_ID < 50207) {
        define('PHP_MAJOR_VERSION',   $version[0]);
        define('PHP_MINOR_VERSION',   $version[1]);
        define('PHP_RELEASE_VERSION', $version[2]);
    }
}
if (PHP_VERSION_ID < 50300) {
    include_once('php-5.2-.php');
} else {
    include_once('php-5.3+.php');
}