Вызывать методы объектов в массиве с помощью array_map?
Предположим, что у меня есть простой класс:
class MyClass {
private $_prop;
public function getProp() {return $this->_prop;}
[....]
}
Теперь то, что я хочу сделать где-то не в области MyClass
, - это получить массив $_prop из массива объектов MyClass
($objs
). Это, конечно, можно сделать с помощью кода:
$props = array();
foreach ($objs as $obj) {
$props[] = $obj->getProp();
}
Однако это требует цитаты некоторых строк, esp, когда они формируются таким образом (и я должен использовать такое форматирование). Итак, вопрос: если это можно сделать с помощью array_map? Одним из способов было бы использовать функцию create, но мне это не очень нравится в php (lambdas в php, по крайней мере, неудобно, и если я правильно понимаю, его производительность похожа на производительность кода, но производительность здесь не указана). Я устал искать совсем немного и не нашел определенного ответа. Но у меня есть ощущение, что это невозможно. Я пробовал такие вещи, как array_map(array('MyClass', 'getProp'), $objs)
, но это не работает, поскольку метод не является статическим.
Изменить: я использую php 5.3.
Ответы
Ответ 1
В PHP 5.3 вы можете:
$props = array_map(function($obj){ return $obj->getProp(); }, $objs);
(см. анонимные функции)
Конечно, это все равно будет медленнее, чем использование цикла for
, поскольку у вас есть один вызов функции для каждого элемента, но я думаю, что это ближе всего к тому, что вы хотите.
В качестве альтернативы, который также работает до PHP 5.3 и может соответствовать вашим правилам стиля:
function map($obj) {
return $obj->getProp();
}
$props = array_map('map', $objs);
Или (снова вернемся к PHP 5.3), вы можете создать такую оберточную функцию (но это будет самая медленная возможность, я думаю):
function callMethod($method) {
return function($obj) use ($method) {
return $obj->{$method}();
};
}
$props = array_map(callMethod('getProp'), $objs);
Ответ 2
Попробуйте этот код и посмотрите, почему вы действительно хотите использовать foreach
вместо структуры array_map
(это очень упрощенный тест, но он показывает точку):
error_reporting(E_ALL ^ E_STRICT);
ini_set('display_errors', 'on');
class MyClass
{
private $_prop;
public function getProp() {
return $this->_prop;
}
}
$objects = array();
for ($i = 0; $i <= 1000; $i += 1) {
$array[] = new MyClass;
}
// using foreach
$start = microtime(true);
for ($i = 0; $i <= 1000000; $i += 1) {
$props = array();
foreach ($objects as $object) {
$props[] = $object->getProp();
}
}
printf('%.5fs', microtime(true) - $start);
// using inline anonymous function
$start = microtime(true);
for ($i = 0; $i <= 1000000; $i += 1) {
$props = array_map(function ($object) {
return $object->getProp();
}, $objects);
}
printf('<br />%.5fs', microtime(true) - $start);
// using stored anonymous function
$start = microtime(true);
$propGetter = function ($object) {
return $object->getProp();
};
for ($i = 0; $i <= 1000000; $i += 1) {
$props = array_map($propGetter, $objects);
}
printf('<br />%.5fs', microtime(true) - $start);