Возможен ли обратный вызов в стиле 'invoke' в PHP5?

StackOverflow https://stackoverflow.com/questions/824834

  •  05-07-2019
  •  | 
  •  

Вопрос

PHP-функции, такие как array_map, принимают обратный вызов, который может быть простой функцией или методом класса или объекта:

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

или

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

Но существует ли синтаксис для передачи метода, который в рамках итерации связан с текущим объектом (например, «invoke» в Prototype.js)? Чтобы можно было использовать следующее:

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

с эффектом

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

Очевидно, я могу использовать эту форму или написать функцию-обертку, чтобы сделать вызов, и даже сделать это встроенным. Но так как «myMethod» уже является методом, кажется, нужно обходить дома, чтобы сделать один из них.

Это было полезно?

Решение

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);

Другие советы

В настоящее время нет. Когда выйдет php 5.3, вы можете использовать следующий синтаксис:

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

В основном нет. Не существует специального синтаксиса, чтобы сделать это проще.

Я могу придумать более причудливый способ сделать это в PHP 5.3, поскольку в PHP всегда есть несколько способов сделать что-то, но я бы сказал, что это не обязательно будет лучше . чем ваш пример foreach :

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

Просто продолжай свой 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);

?>

вуаля!

Это немного глупый ответ, но вы можете создать подкласс ArrayObject и использовать его вместо обычного массива:

<?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));

Выводит это

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

Я бы использовал create_function () , чтобы ... ну ... создать временную функцию для array_map во время ожидания PHP 5.3

$func = create_function('$o', '$o->myMethod();');
array_map($func, $objects);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top