7

Is there a way to make this code work without a Warning?

function myFunction($value, $key, &$array)
{
     if (strlen($value)<=2) $array[] = $key.$value;
}
$a = array("aa", "bbb", "cc", "dd");
$resultA = array();
array_walk($a, 'myFunction', &$resultA);
// now '$resultA' should contain: Array([0] => aa0 [1] => cc2 [2] => dd3)

It works, but it always throws this warning message:

Warning: Call-time pass-by-reference has been deprecated in path_to\index.php on line 7

I thought that removing the ampersand from the call should be enough to make the warning disappear, and it is, but, strangely the "array_walk" doesn't acomulate the third parameter if I just specify the & in "myFunction". To make it work there has to be an & in the call too, but then it will trigger the warning.

Further, as a temorary workaround I have tried to set the php.ini var "allow_call_time_pass_reference" to true, but I still get the warning...

I'm wondering that may be there's better/preferred method to apply user-defined functions to each element of an array WITH a passed-by-reference parameter.

Toni Rosa
  • 318
  • 1
  • 3
  • 8

2 Answers2

16

The short answer is that you can't do that with array walk. However, you do have some alterantives:

Using a closure (available in PHP >= 5.3.0):

$myArray = array();
$callback = function ($key, $value) use (&$myArray) {
    if (strlen($value) <= 2) {
        $myArray[] = $key . $value;
    }
};
array_walk($a, $callback);

Create a filter iterator (Note that this is likely way overkill):

class myFilterIterator extends FilterIterator {
    public function accept() {
        return strlen(parent::current()) <= 2;
    }
    public function current() {
        return parent::key() . parent::current();
    }
}
$it = new myFilterIterator(new ArrayIterator($a));
$newArray = iterator_to_array($it);

There are other ways, but you're appending of key and value really makes things difficult for mapping style solutions...

Digital Fu
  • 2,877
  • 1
  • 14
  • 20
ircmaxell
  • 163,128
  • 34
  • 264
  • 314
  • I can't use clousures with php 5.2. I will go for txyoji solution as it seems simpler to me specialy because I didn't know about the FilterIterator abstract class, and thus it's more similar to "my average" php code. In any case, thanks for the suggestion! – Toni Rosa Mar 01 '11 at 15:52
  • 2
    In the first solution parameters are in the wrong order. They should be ($value, $key) – hyponym Jun 15 '17 at 11:24
4

The third parameter to array_walk isn't passed by reference so that's not going to work. Instead of a function, you can use an object method as a callback and accumulate the results in the object.

Class myClass
{
 public values;
 public function myCallback($value,$key)
 {
   if (strlen($value)<=2){
       $this->values[] = $key.$value;
   }
 }
}
$a = array("aa", "bbb", "cc", "dd");
$obj = new myClass();
array_walk($a, array($obj,'myCallback'));

or you could define a global inside the callback function.

function myFunction($value, $key)
{
   global $array;    
   if (strlen($value)<=2) $array[] = $key.$value;
}

both are valid.

txyoji
  • 6,680
  • 1
  • 44
  • 46