Passing by reference does not work with additional parameters for array_walk_recursive, if only this is an outdated call forwarding

For a while, I used a "traditional" recursive function to smooth multidimensional arrays, such as

$baseArray = array(array('alpha'), array('beta','gamma'), array(), array(array('delta','epsilon'), array('zeta',array('eta', 'theta' ), ), ), array('iota'), ); 

to a simple 1-dimensional array.

Last night, I thought I'd see how to use array_walk_recursive () to find out if I could make it more efficient and clean.

My first attempt was not very successful:

 function flattenArray($arrayValue, $arrayKey, &$flatArray) { $flatArray[] = $arrayValue; } $flattenedArray = array(); array_walk_recursive($baseArray,'flattenArray',$flattenedArray); 

I thought this would work, but all I had was a series of errors:

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

and the result:

 array(0) { } 

The hint type in my flattenArray () function gave me

 Catchable fatal error: Argument 3 passed to flattenArray() must be an array, integer given in C:\xampp\htdocs\arrayTest.php on line 16 

Using closures gave identical results.

The only way I could get it to work (without using global or static for my flattenedArray) used a call time callback:

 function flattenArray($arrayValue, $arrayKey, $flatArray) { $flatArray[] = $arrayValue; } $flattenedArray = array(); array_walk_recursive($baseArray,'flattenArray',&$flattenedArray); 

which gives the correct result

 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" } 

but gives me an unexpected warning

 Deprecated: Call-time pass-by-reference has been deprecated in C:\xampp\htdocs\arrayTest.php on line 22 

I know that PHP is a fancy language, but it seems a bit extreme. The documentation clearly shows that the first parameter to array_walk_recursive is pass by reference, but it seems that additional arguments can only be pass by reference during a call. Weird!

PHP Version - 5.3.8

Any suggestions on how I can use array_walk_recursive to smooth my array correctly, without getting obsolete errors (besides reporting an error).

EDIT

PS

I know that I can get around this problem using closure:

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

but since this is required for a library that currently allows it to be used with PHP 5.2.0, this is not a practical use case for a function that requires a much later version of PHP

+6
source share
4 answers

Think of it this way: you pass $flatArray to array_walk_recursive by value . array_walk_recursive will then pass the argument by reference to your function. But as it has been passed to array_walk_recursive by value, the link will point to another value.

I know this may seem like a strange limitation, but when you think about it, it is also quite logical.

By the way, I think that you accidentally also discovered another problem with this, it actually looks like a serious memory corruption (look at the third elements of the array printed by @ http://codepad.viper-7.com/ZYNrNd ). I will consider this.

On the one hand, a simple way to smooth out uses the RecursiveArrayIterator :

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

Not particularly useful at this stage.

Reading through PHP docs, I found that call_user_func () has a note against it describing the argument arguments:

Please note that the parameters for call_user_func () are not passed a link.

but array_walk_recursive () does not have such a notification.

This could be a problem with the documentation ... if I saw a similar notification in the documentation of array_walk_recursive (), I probably would not try (although a curious one could try it independently, just to find out what happened).

However, I don’t understand why, when defining a callback function, both arguments should not accept pass-by-reference arguments. This is a bit like a step back ... a language function that really worked (albeit using call time forwarding) no longer does this without relying on this deprecated function.

+1
source

Since your decisions depend on the version (according to the documentation, PHP 5.2 should not complain about call-time pass-by-reference ), one option is to create different scripts associated with each implementation, and then another script conditionally includes a script that defines a smoothing function (and any other version-specific code) depending on the version of 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'); } 
+1
source

Link passing during a call is out of date:

http://uk3.php.net/manual/en/ini.core.php#ini.allow-call-time-pass-reference

This is not noted in the array_walk_recursive documentation, as it does not apply to this function.

One thing you can do is pass the name of the object and method, not the name of the function, as a callback and save the state of the flattened array as a member of that object.

eg.

 class ArrayFlattener { //implementation and array state } $flattener = new ArrayFlattener(); array_walk_recursive($baseArray, array($flattener, 'flatten')); print_r($flattener->getFlattenedArray()); 
0
source

Source: https://habr.com/ru/post/904228/


All Articles