【问题标题】:array_map and pass 2 arguments to the mapped function - array_map(): Argument #3 should be an arrayarray_map 并将 2 个参数传递给映射函数 - array_map():参数 #3 应该是一个数组
【发布时间】:2015-02-20 09:07:00
【问题描述】:

我有一个如下所示的抽象类:

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 应该是一个数组

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

有什么想法吗?

【问题讨论】:

    标签: php laravel laravel-4


    【解决方案1】:

    请始终阅读文档:

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

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

    但你将 bool $format 作为参数传递

    "调用array_map函数时如何传递2个或更多参数 在一个班级里?

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

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

    【讨论】:

      【解决方案2】:

      您不能使用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);
      

      你明白了:

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

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

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

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

      【讨论】:

        【解决方案3】:

        大多数答案表明,带有 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,因为它可能更有效且更易于阅读。这也将防止您的索引被重新编号,以及使用 TraversableArrayAccess 项目。

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

        编辑:

        我最近意识到还有另一个选项可用,因为您正在使用实例来转换数据。它涉及将$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);
                }
                // ...
            }
        
            // ...
        }
        

        【讨论】:

          【解决方案4】:

          这可能不适用于 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);
          

          所以,这是一个动态使用,通过在 php 的匿名函数下面的 Closure 类上使用调用方法。如果回调是一个数组,它会将-&gt;call 的范围绑定到第一个数组元素,它应该是方法的对象。

          【讨论】:

            猜你喜欢
            • 2019-10-23
            • 2016-02-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-07
            • 2021-04-13
            相关资源
            最近更新 更多