php array_map 并将 2 个参数传递给映射函数 - array_map():参数 #3 应该是一个数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27599767/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 23:25:43  来源:igfitidea点击:

array_map and pass 2 arguments to the mapped function - array_map(): Argument #3 should be an array

phplaravellaravel-4

提问by Latheesan

I have an abstract class that looks like this:

我有一个看起来像这样的抽象类:

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

}

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']
        ];
    }

}

When this code runs, I get the error:

当此代码运行时,我收到错误消息:

array_map(): Argument #3 should be an array

array_map():参数 #3 应该是一个数组

How do you pass 2 or more arguments when you call array_mapfunction within a class? I checked the PHP Documentation and it looks like this is allowed, but it isn't working on my Larave 4.2 project.

array_map在类中调用函数时如何传递 2 个或更多参数?我检查了 PHP 文档,看起来这是允许的,但它不适用于我的 Larave 4.2 项目。

Any ideas?

有任何想法吗?

回答by Peter

Please always read docs:

请始终阅读文档:

http://php.net/manual/en/function.array-map.php

http://php.net/manual/en/function.array-map.php

array array_map ( callable $callback , array $array1 [, array $... ] )

and yet you pass bool $formatas argument

然而你传递 bool$format作为参数

"How do you pass 2 or more arguments when you call array_map function within a class?

“在类中调用 array_map 函数时,如何传递 2 个或更多参数?

I would create anonymous function with use()syntax

我会用use()语法创建匿名函数

public function transformCollection(array $items, $format)
{
    return array_map(function($item) use ($format) {
        return $this->transform($item, $format);
    }, $items);
}

回答by alexrussell

You can't use array_mapto pass hard-coded values to a callback function (what is commonly referred to as curryingor partially-applied functions in functional languages). What array_maptakes is a variable amount of arrays, all of which should have the same amount of elements. The element at the current index of each array is passed to the callback as separate arguments. So, for instance, if you do this:

您不能使用array_map将硬编码值传递给回调函数(currying在函数式语言中通常称为或部分应用的函数)。什么array_map需要的是阵列可变量的,所有这些都应该有元件的相同的量。每个数组当前索引处的元素作为单独的参数传递给回调。因此,例如,如果您这样做:

$arr1 = [1, 2, 3, 4];
$arr2 = [2, 4, 6, 8];

$func = function ($a, $b) { return $a.'-'.$b; };


$arr3 = array_map($func, $arr1, $arr2);

You get this:

你得到这个:

['1-2', '2-4', '3-6', '4-8']

Hopefully that explains the idea behind it - each array you pass in will have the element at the current position in the first array passed as the relevant parameter to the callback function.

希望这解释了它背后的想法 - 您传入的每个数组都会将第一个数组中当前位置的元素作为相关参数传递给回调函数。

So, as I said, it's not to be used for passing 'static' values to the callback. However, you can do this yourself by defining an anonymous function on the fly. In your transformCollectionmethod:

所以,正如我所说,它不能用于将“静态”值传递给回调。但是,您可以通过动态定义匿名函数来自己完成此操作。在你的transformCollection方法中:

return array_map(function ($item) use ($format) {
    return $this->transform($item, $format);
}, $items);

回答by Shaun Cockerill

Most answers show that an anonymous function with the usekeyword is the typical way to pass additional arguments through to other callables.

大多数答案表明,带有use关键字的匿名函数是将附加参数传递给其他可调用对象的典型方式。

abstract class Transformer {
    public function transformCollection(array $items, $format)
    {
        return array_map(function($item) use ($format) {
            return $this->transform($item, $format);
        }, $items);
    }
}

Most likely though, this particular situation would be better suited by a standard foreachloop over array_map, as it would potentially be more efficient and easier to read. This would also prevent your indexes from being renumbered, as well as work with Traversableand ArrayAccessitems.

不过,最有可能的是,这种特殊情况更适合标准foreach循环array_map,因为它可能更高效且更易于阅读。这也将防止您的索引被重新编号,以及使用TraversableArrayAccess项目。

abstract class Transformer {
    public function transformCollection(array $items, $format)
    {
        foreach($items as $key => $item) {
           $items[$key] = $this->transform($item, $format);
        }
        return $items;
    }
}

If you really, reallyhave your heart set on using array_map, anonymous functions don't work with your environment (i.e. pre PHP 5.3) and you need to pass $formatthrough as the 2nd argument, then you will need to convert $formatto an array with the same length as $items.

如果您真的,真的很想使用array_map,匿名函数不适用于您的环境(即 PHP 5.3 之前)并且您需要$format作为第二个参数传递,那么您将需要转换$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);
    }
}

EDIT:

编辑:

I realised recently that there was another option available since you're using an instance to transform your data. It involves storing $formatto the instance, possibly using a setter, and overriding it if it is provided as an argument. This way it's accessible via the transform method using $this->format.

我最近意识到还有另一种选择,因为您正在使用实例来转换数据。它涉及存储$format到实例,可能使用 setter,如果它作为参数提供,则覆盖它。这样就可以通过使用$this->format.

abstract class Transformer {
    protected $format;

    public function setFormat($format)
    {
        $this->format = $format;
    }

    public function transformCollection(array $items, $format = null)
    {
        if (isset($format)) {
            $this->setFormat($format);
        }
        // ...
    }

    // ...
}

回答by imme

This may not be applicable for laravel 4.2 // pre php 5.3 (as Shaun mentions) but might come in handy for some people who come across this question.

这可能不适用于 laravel 4.2 // pre php 5.3(正如 Shaun 提到的),但对于遇到这个问题的一些人来说可能会派上用场。

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

So, that's a dynamic use, by using the call-method on the Closure-class that's underneath php's anonymous functions. If the callback is an array, it will bind the scope of the ->callto the first array-element, which should be the method's object.

因此,这是一种动态使用,通过在 php 匿名函数下的 Closure 类上使用调用方法。如果回调是一个数组,它将把 的范围绑定->call到第一个数组元素,它应该是方法的对象。