Array map и передать 2 аргумента сопоставленной функции-array map (): Аргумент #3 должен быть массивом
у меня есть абстрактный класс, который выглядит так:
abstract class Transformer {
/**
* Transform a collection of items
*
* @param array $items
* @param bool $format
* @return array
*/
public function transformCollection(array $items, $format)
{
return array_map([$this, 'transform'], $items, $format);
}
/**
* Transform a item
*
* @param array $item
* @param bool $format
* @return mixed
*/
public abstract function transform(array $item, $format);
}
тогда у меня есть следующий класс, который реализует его:
class ServiceLogTransformer extends Transformer {
public function transform(array $service_log, $format = false)
{
return [
'id' => $service_log['id'],
'date' => $service_log['log_date'],
'time' => $service_log['log_time'],
'type' => ($format ? status_label($service_log['log_type']) : $service_log['log_type']),
'entry' => $service_log['log_entry']
];
}
}
когда этот код запускается, я получаю сообщение об ошибке:
array_map (): Аргумент #3 должен быть массивом
как вы проходите 2 или более аргументов при вызове array_map
функции внутри класса? Я проверил документацию PHP, и похоже, что это разрешено, но он не работает на моем Larave 4.2 проект.
какие идеи?
4 ответов
пожалуйста, всегда внимательно читайте документы:
http://php.net/manual/en/function.array-map.php
array array_map ( callable $callback , array $array1 [, array $... ] )
и все же вы проходите bool $format
в качестве аргумента
" как передать 2 или более аргументов при вызове функции array_map в классе?
Я бы создал анонимную функцию с use()
синтаксис
public function transformCollection(array $items, $format)
{
return array_map(function($item) use ($format) {
return $this->transform($item, $format);
}, $items);
}
вы не можете использовать array_map
для передачи жестко закодированных значений функции обратного вызова (что обычно называют currying
или частично применяемые функции на функциональных языках). Что?!--3--> занимает разное количество массивов, которые должны иметь одинаковое количество элементов. Элемент с текущим индексом каждого массива передается обратному вызову в виде отдельных аргументов. Так, например, если вы сделаете это:
$arr1 = [1, 2, 3, 4];
$arr2 = [2, 4, 6, 8];
$func = function ($a, $b) { return $a.'-'.$b; };
$arr3 = array_map($func, $arr1, $arr2);
вы получили это:
['1-2', '2-4', '3-6', '4-8']
надеюсь это объясняет идею этого-каждый массив, который вы передаете, будет иметь элемент в текущей позиции в первом массиве, переданный в качестве соответствующего параметра функции обратного вызова.
Итак, как я уже сказал, он не должен использоваться для передачи "статических" значений в обратный вызов. Однако вы можете сделать это самостоятельно, определив анонимную функцию на лету. В transformCollection
способ:
return array_map(function ($item) use ($format) {
return $this->transform($item, $format);
}, $items);
большинство ответов показывают, что анонимная функция с use
ключевое слово-это типичный способ передачи дополнительных аргументов другим вызываемым объектам.
abstract class Transformer {
public function transformCollection(array $items, $format)
{
return array_map(function($item) use ($format) {
return $this->transform($item, $format);
}, $items);
}
}
скорее всего, хотя, эта конкретная ситуация будет лучше соответствовать стандарту foreach
цикл array_map
, поскольку это потенциально было бы более эффективно и легче читать. Это также предотвратит перенумерование ваших индексов, а также работу с Traversable
и ArrayAccess
предметы.
abstract class Transformer {
public function transformCollection(array $items, $format)
{
foreach($items as $key => $item) {
$items[$key] = $this->transform($item, $format);
}
return $items;
}
}
если вы действительно, действительно ваше сердце настроено на использование array_map
, анонимные функции не работают с вашей средой (т. е. pre PHP 5.3), и вам нужно передать $format
через как 2-й аргумент, то вам нужно будет преобразовать $format
массиву той же длины, что и $items
.
abstract class Transformer {
public function transformCollection(array $items, $format)
{
// Fill an array of same length as $items with the $format argument.
$format = array_fill(0, count($items), $format);
return array_map([$this, 'transform'], $items, $format);
}
}
Это может быть неприменимо для laravel 4.2 / / pre php 5.3 (как упоминает Шон), но может пригодиться для некоторых людей, которые сталкиваются с этим вопросом.
abstract class Transformer {
/**
* Transform a collection of items
*
* @param array $items
* @param bool $format
* @return array
*/
public function transformCollection(array $items, $format)
{
$args = func_get_args();
return $this->mapWith([$this, 'transform'], $args);
}
/**
* @param callback<array|string> $callback
* @param array $args first a collection to disect, then optional additional arguments to the callback
* @return array
*/
private function mapWith($callback, $args) {
$data = array_shift($args);
$closure = \Closure::fromCallable($callback);
$scope = \is_array($callback) ? $callback[0] : null;
return array_map(function ($item) use ($scope, $closure, $args) {
array_unshift($args, $item);
if (null !== $scope) {
array_unshift($args, $scope);
$closure = [$closure, 'call'];
}
return \call_user_func_array($closure, $args);
}, $data);
}
/**
* Transform a item
*
* @param array $item
* @param bool $format
* @return mixed
*/
public abstract function transform(array $item, $format);
}
function status_label($index){return vsprintf('label: %s', [$index,]);}
#Then I have the following class that implements it:
class ServiceLogTransformer extends Transformer {
public function transform(array $service_log, $format = false)
{
return [
'id' => $service_log['id'],
'date' => $service_log['log_date'],
'time' => $service_log['log_time'],
'type' => ($format ? status_label($service_log['log_type']) : $service_log['log_type']),
'entry' => $service_log['log_entry']
];
}
}
$logs = [
['id' => 123454, 'log_date'=>'20180926', 'log_time'=>'151913', 'log_type'=>'q', 'log_entry' => 'lorem',],
['id' => 353454, 'log_date'=>'20180926', 'log_time'=>'152013', 'log_type'=>'r', 'log_entry' => 'dolor',],
];
$slt = new ServiceLogTransformer();
$new = $slt->transformCollection($logs, false);
$lab = $slt->transformCollection($logs, true);
var_dump($logs);
var_dump($new);
var_dump($lab);
таким образом, это динамическое использование, используя метод вызова для класса закрытия, который находится под анонимными функциями php. Если обратный вызов является массивом, он свяжет область ->call
к первому элементу массива, который должен быть объектом метода.