5

PHP has some great functions (like array_walk) that allow you to process each element in an array. They're generally set up so you specify the array you want processed as the first parameter and a callback function to apply to each element as the second. These functions return booleans indicating success, not a copy of the modified array as you might expect. If you want the array to be modified, you have to pass the array in by reference like array_walk(&$my_array, 'my_callback');

However, in PHP 5.3 and above, if you pass by reference to function call you get a E_DEPRECATED error.

Does anyone know (if there exists) a correct way to use these functions to modify arrays without triggering the errors and without explicitly suppressing them? Are there newer alternatives to these old array processing functions.

hakre
  • 193,403
  • 52
  • 435
  • 836
Ray
  • 40,256
  • 21
  • 101
  • 138

3 Answers3

7

Values are passed by reference implicitly in PHP >= 5.3 as determined by the function definition.

Function definition for array_walk():

bool array_walk ( array &$array , callable $funcname [, mixed $userdata = NULL ] )

Note &$array. As such, you do not need to explicitly pass the array by reference in the function call in PHP >= 5.3.

array_walk($my_array, 'my_callback');

However, you will need to ensure that the callback accepts it's value by reference accordingly (as demonstrated by nickb).

Also take a look at PHP 5.4 Call-time pass-by-reference - Easy fix available?

Community
  • 1
  • 1
Jason McCreary
  • 71,546
  • 23
  • 135
  • 174
  • Ah... thanks, makes sense. Interesting nuance--you can't call by reference, but you can define a function/method with arguments which are referenced. http://php.net/manual/en/language.references.pass.php I still wish those functions returned copies of modified arrays or null instead of booleans! – Ray Jul 23 '12 at 16:39
  • Yes, exactly. Glad to help out. – Jason McCreary Jul 23 '12 at 16:58
6

Because you should be defining the callback to accept its parameter by reference to modify the array.

array_walk( $my_array, function( &$el, $key) { $el = $el / 2; });

So a quick example like this:

$my_array = range( 2, 10, 2);
array_walk( $my_array, function( &$el, $key) { $el = $el / 2; });
var_dump( $my_array);

Will output:

array(5) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
}
nickb
  • 59,313
  • 13
  • 108
  • 143
  • Thanks for the feedback, but Jasons answer below which added to your made the reference issue clearer. You still got an upvote from me though! – Ray Jul 23 '12 at 16:39
1

You can also pass an argument for the callback as the third parameter of array_walk. The problem is how to pass a reference as the callback argument. This used to be possible using the & prefix when calling array_walk. This is deprecated and subsequently made illegal. Defining the callback with a reference-type third parameter doesn't help here.

A workaround could be to pass a reference inside an array (&$var is allowed as argument of 'array'!) as the third argument and dereference the array in the callback to obtain the reference again, like so:

function cb(&$v, $k, $ar) {
  $v='bla'.$k;
  $ar[0]++;
}
$count=0;
$arr = array('sint'=>'er','kla'=>'aas','en'=>'zwartepiet');
array_walk($arr,'cb',array(&$count));
var_dump($arr,$count);

Which prints:

array(3) {
  ["sint"]=>
  string(7) "blasint"
  ["kla"]=>
  string(6) "blakla"
  ["en"]=>
  string(5) "blaen"
}
int(3)

When call-time references were still allowed, it used to be possible like so:

function cb(&$v, $k, $ref) {
  $v='bla'.$k;
  $ref++;
}
$count=0;
$arr = array('sint'=>'er','kla'=>'aas','en'=>'zwartepiet');
array_walk($arr,'cb',&$count);
var_dump($arr,$count);
Roho
  • 66
  • 2