Question

PHP functions such as 'array_map' take a callback, which can be a simple function or a class or object method:

$array2 = array_map('myFunc', $array);  

or

$array2 = array_map(array($object, 'myMethod'), $array);

But is there a syntax to pass a method which is bound within the iteration to the current object (like 'invoke' in Prototype.js)? So that the following could be used:

$array2 = array_map('myMethod', $array);

with the effect of

foreach($array as $obj) $array2[] = $obj->myMethod();

Obviously I can use this form, or I can write a wrapper function to make the call, and even do that inline. But since 'myMethod' is already a method it seems to be going round the houses to have to do one of these.

Was it helpful?

Solution

function obj_array_map($method, $arr_of_objects) {
    $out = array();
    $args = array_slice(func_get_args(), 2);
    foreach ($arr_of_objects as $key => $obj) {
        $out[$key] = call_user_func_array(Array($obj, $method), $args);
    }
    return $out;
}

// this code
$a = Array($obj1, $obj2);
obj_array_map('method', $a, 1, 2, 3);

// results in the calls:
$obj1->method(1, 2, 3);
$obj2->method(1, 2, 3);

OTHER TIPS

Not currently. When php 5.3 comes out, you could use the following syntax:

$array2 = array_map(function($obj) { return $obj->myMethod(); }, $array);

Basically, no. There is no special syntax to make this any easier.

I can think of a fancier way of doing this in PHP 5.3, seeing as there's always more than one way to do things in PHP, but I'd say it wouldn't necessarily be better than your foreach example:

$x = array_reduce(
    $array_of_objects, 
    function($val, $obj) { $val = array_merge($val, $obj->myMethod()); return $val; },
    array() 
);

Just go with your foreach :)

<?php

// $obj->$method(); works, where $method is a string containing the name of the
// real method
function array_map_obj($method, $array) {
    $out = array();

    foreach ($array as $key => $obj)
        $out[$key] = $obj->$method();

    return $out;    
}

// seems to work ...

class Foo {
    private $y = 0;
    public function __construct($x) {
        $this->y = $x;
    }
    public function bar() {
        return $this->y*2;
    }
}

$objs = array();
for ($i=0; $i<20; $i++)
    $objs[] = new Foo($i);

$res = array_map_obj('bar', $objs);

var_dump($res);

?>

voila!

This is a bit of a silly answer, but you could subclass ArrayObject and use that instead of a normal array:

<?php

class ArrayTest extends ArrayObject {
    public function invokeMethod() {
        $result = array();
        $args = func_get_args();
        $method = array_shift($args);
        foreach ($this as $obj) {
            $result[] = call_user_func_array(array($obj, $method), $args);
        }
        return $result;
    }
}

//example class to use
class a { 
    private $a;
    public function __construct($a) { 
        $this->a = $a; 
    }

    public function multiply($n) {
        return $this->a * $n;
    }
 }

//use ArrayTest instance instead of array
$array = new ArrayTest();
$array[] = new a(1);
$array[] = new a(2);
$array[] = new a(3);

print_r($array->invokeMethod('multiply', 2));

Outputs this:

Array
(
    [0] => 2
    [1] => 4
    [2] => 6
)

I would use create_function() to ... well ... create a temporary function for array_map while waiting for PHP 5.3

$func = create_function('$o', '$o->myMethod();');
array_map($func, $objects);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top