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 к первому элементу массива, который должен быть объектом метода.