【问题标题】:PHP Good practices - Methods with too many parametersPHP 良好实践 - 参数过多的方法
【发布时间】:2011-09-28 08:18:17
【问题描述】:

我制作了一个类和方法,仅用于在我的网站上搜索内容。它有太多的参数,搜索参数。我的控制器从表单中抓取数据,然后传递给模型。

public function search($name, $age, $foo, ... $bar, $lorem) {

这种方法有什么技巧吗?参数过多的方法可能是一个很好的做法。 谢谢。

编辑:

参数用于搜索... $name 应该搜索价值为 $name 的人 $age 应该搜索价值为 $age 的人 等等... 类似于 SQL Where 子句。

再次感谢。

【问题讨论】:

  • 传递一个包含每个参数作为数组元素的数组。
  • @MarcB:你为什么不把它作为答案发布?
  • 通常这表明该方法过于复杂/强大。您应该分解功能。
  • 这没有灵丹妙药。方法很具体。数组是一种可能性,但并不总是合适的。您为什么不完整地发布方法,或者至少发布签名并(详细)描述各个参数的作用,当然还有方法的作用! 编辑:“如何?”通过扩展您的问题,我们可以提供帮助;)
  • 啊,我不能对评论投反对票。只有upvote - 这是错误的。所以,马克 B,-1 为您的评论。

标签: php search methods parameters arguments


【解决方案1】:

DarhazerZanathel 已经给出了很好的答案,我只想向您展示一件事:具有流畅界面的 setter。仅当所有参数都是可选的。

$finder->
 setName($name)->
 setAge($age)->
 setFoo($foo)->
 setBar($bar)->
 setLorem($lorem)->
 search();

$query = new SearchQuery($required_argument);
$query->setAge($optional)->setLorem($optional);

$finder->search($query);

要创建fluent interface,只需在setter的正文中写入return $this;

【讨论】:

    【解决方案2】:

    我喜欢将数组用于可能/具有许多参数的函数。这种方法可以实现近乎无限的参数扩展,并且比使用func_get_args() 之类的方法更直接、更好。

    public function search(array $options = array())
    {
        $defaults = array(
            'name'   => null,
            'age'    => null,
            'order'  => null,
            'limit'  => null,
            'offset' => null,
        );
        $options = array_merge($defaults, $options);
    
        extract($options);
    
        $select = $this->select();
    
        if (!is_null($name)) {
            $select->where('name = ?', $name);
        }
        if (!is_null($age)) {
            $select->where('age = ?', $age, Zend_Db::INT_TYPE);
        }
        if (!is_null($order)) {
            $select->order($order);
        }
        if (!is_null($limit) || !is_null($offset)) {
            $select->limit($limit, $offset);
        }
    
        $results = $this->fetchAll($select);
    
        return $results;
    }
    

    ...或者您可以使用面向对象的方法:

    class SearchQuery
    {
        public function __construct(array $options = null)
        {
            if (!is_array($options)) {
                return;
            }
    
            if (array_key_exists('name', $options)) {
                $this->setName($options['name']);
            }
            if (array_key_exists('age', $options)) {
                $this->setAge($options['age']);
            }
        }
    
        public function setName($name)
        {
            if (!is_string($name)) {
                throw InvalidArgumentException('$name must be a string');
            }
    
            $this->_name = $name;
    
            return $this;
        }
    
        public function setAge($age)
        {
            if (!is_numeric($age) || $age <= 0) {
                throw new InvalidArgumentException('$age must be a positive integer');
            }
    
            $this->_age = $age;
    
            return $this;
        }
    }
    
    // then you can use dependency injection in your main search class
    
    class SearchService
    {
        public function search(SearchQuery $query)
        {
            // search
        }
    }
    

    【讨论】:

      【解决方案3】:

      你可以把东西打包成一个键=>基于值的数组

      例子:

      $params = array("Name"=>"Bob", "Age"=32.....);
      Class->search($params);
      public function search($params) {
          // access keys
      }
      

      这有点令人厌烦,因为可以传入任何数组,因此很容易错误地使用该方法。在其他一些方法调用中可能需要进行一些验证以验证数组内容。

      编辑:由于在 cmets 中存在一些争论......这是另一种方法

      创建一个新类!包含姓名年龄等以及其他任何人口统计数据的用户类。无论如何,您可能会在其他地方使用它们。

      将一个或多个对象作为参数传入

      $object = new Object();
      SearchClass->search($object)
      
      public function search(Object $object){
           // Do junk here
      }
      

      【讨论】:

      • 你总是可以将任何参数传递给一个方法...拥有一个数组并不会让“错误地”使用它变得更容易。
      • 这个对于可选参数来说是可以的,但在我看来它不适合必需参数,因为你必须检查方法的主体以查看所需的键。此外,它使正文更长,因为您必须检查给定参数是否被传递(并提供默认值)
      • @phant0m 如果您在函数中定义了一组 REQUIRED 参数,那么您就知道它需要这些参数。通过使用数组,您可以传入错误数量的函数可能需要正确执行的参数。就像我说的那样,您必须为所述必需参数创建一个验证方法,以便在它们不正确时抛出异常。因此,更容易误用。特别是如果客户正在使用代码并且不熟悉它。
      • @Darhazer 我同意。这会导致一些粗略的代码,并且将来可能会出现一些调试问题。需要的参数应该单独传入。
      • 这不仅不好,因为您不知道哪些参数是可选的,哪些不是。这很糟糕,因为您必须在内存中保留该数组(!)的字段的所有名称和数据类型,,因为 IDE 将无法为您提供自动完成建议。
      【解决方案4】:

      我将使用与value objects 最接近的比喻,您将包含所有必要参数的一个对象作为属性传递给函数。

      <?php
      class FilterVO {
          public $id;
          public $name;
          // etc ...
      }
      
      class SomeCollection {
          public function FilterResults(FilterVO $prefs) {
              // got all the goodies in here
          }
      }
      ?>
      

      【讨论】:

      • 您可以执行以下操作,而不是检查 $prefs:public function FilterResults(FilterVO $prefs) ... 谢谢。
      • 问题的作者纠正答案很好:)
      • 嘿嘿,付出与收获! :D 谢谢!
      【解决方案5】:

      【讨论】:

      • 已经-2(我的+1)。 @Darhazer,您的答案只是一个正确的答案,但是,也许您可​​以在链接中写超过 3 个字的内容? :)
      • @OZ_,当参数是 $foo、$bar 和 $lorem 时很难解释如何重构它们 ;) 你知道 - 问题包含答案的一半,或者答案是相同的质量问题。无论如何,感谢批评者,我同意一些解释将是有用的,以激励读者阅读有关此重构的更多信息:)
      【解决方案6】:

      让它接受一个包含许多名称-值对的数组作为参数。然后您可以使用extract($paramsArray) 将数组中的所有名称设为$variables。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-03
        • 2013-06-16
        相关资源
        最近更新 更多