通过数组定义类选项是不好的做法吗?

时间:2010-12-28 22:28:32

标签: php class settings options

当我们看看像Dojo,Mootools,jQuery,JS Prototype等Javascript框架时,我们看到选项通常是通过这样的数组定义的:

dosomething('mainsetting',{duration:3,allowothers:true,astring:'hello'});

在编写PHP类时实现相同的想法是不好的做法吗?

示例:

class Hello {

    private $message = '';
    private $person = '';


    public function __construct($options) {

        if(isset($options['message'])) $this->message = $message;
        if(isset($options['person'])) $this->person = $person;
    }


    public function talk() {

        echo $this->person . ' says: ' . $this->message;
    }
}

常规方法:

class Hello {

    private $message = '';
    private $person = '';


    public function __construct() {}


    public function setmessage($message) {

        $this->message = $message;
    }


    public function setperson($person) {

        $this->person = $person;
    }


    public function talk() {

        echo $this->person . ' says: ' . $this->message;
    }
}

第一个示例中的优点是您可以根据需要传递尽可能多的选项,而类只会提取它所需的选项。

例如,从JSON文件中提取选项时,这可能很方便:

$options = json_decode($options);
$hello = new Hello($options);

这就是我经常这样做的方式:

$options = json_decode($options);
$hello = new Hello();

if(isset($options['message'])) $hello->setmessage($options['message']);
if(isset($options['person'])) $hello->setperson($options['person']);

这种模式是否有名称,您认为这是一种不好的做法吗?

我在示例中留下了验证等,以保持简单。

7 个答案:

答案 0 :(得分:12)

有好的和坏的方面。

好处:

  • 不需要多个方法签名(即支持的重载)
  • 与前一点保持一致:可以使用任何顺序的参数调用方法
  • 可以动态生成参数,而无需指定每个参数(例如:根据用户输入动态创建参数数组并将其传递给函数)
  • 不需要像setNamesetThissetThat等“样板”方法,尽管您可能仍想要包含它们
  • 默认值可以在函数体中定义,而不是签名(jQuery使用这种模式很多。他们经常$.extend传递给具有默认值数组的方法的选项。在你的情况下,你会使用array_merge()

糟糕:

  • 除非您正确宣传每个选项,否则您的课程可能会更难使用,因为很少有人会知道支持哪些选项
  • 当你事先知道需要通过时,再创建一个参数数组还有一步
  • 用户并不总是明白存在默认值,除非提供了文档或者他们可以访问源代码

在我看来,这是一项很棒的技巧。我最喜欢的方面是你不需要提供具有不同签名的重载方法,并且签名不是一成不变的。

答案 1 :(得分:3)

这种方法没有任何问题,特别是如果你需要传递给构造函数的参数很多。这也允许你为它们设置默认值,并在构造函数中设置array_merge()它们(有点像所有jQuery插件那样)

protected $default_params = array(
    'option1' => 'default_value'
);
public function __construct($params = array()) {
    $this->params = array_merge($this->default_params, $params);
}

如果你想要这个“模式”的实例,请查看symfony框架,他们几乎每个地方都使用它:这里是an example of sfValidatorBase constructor

答案 2 :(得分:3)

当你给出参数名称时,它被称为“命名表示法”vs。 “位置表示法”,其中参数必须按特定顺序排列。

在PHP中,您可以传递“options”参数,以提供与其他语言(如Python)相同的效果,您可以使用真正的命名表示法。这不是一个坏习惯,但通常在有充分理由的情况下完成(例如在您的示例中或存在大量参数并且不需要按任何特定顺序设置的情况)。

答案 3 :(得分:1)

我不知道这个名字,但我真的怀疑这是一个不好的做法,因为当你不想宣布一个小的快速功能或类属性时,你通常会使用它

答案 4 :(得分:1)

如果有强制选项,它们应该在构造函数的参数列表中。然后使用默认值添加可选选项。

public function __construc($mandatory1, $mandatory2, $optional1="value", $optional2="value") { }

如果所有选项都是可选的,那么创建一个带数组的构造函数会很有用。创建对象比使用“普通构造函数”更容易:您可以只提供所需的选项,而如果要提供$ optional2,则需要提供“普通构造函数”,您必须提供$ optional1(甚至设置它)到默认值)。

答案 5 :(得分:1)

我不会说它的不良做法,至少如果你相信数据的来源。

另一种可能性是根据options数组键动态调用setter,如下所示:

public function __construct($options) {
    foreach($options as $option => $value) {
        $method = 'set'.$option;
        if(method_exists($this, $method)
            call_user_func(array($this, $method, $value);
    }
}

答案 6 :(得分:0)

为什么不两个都做?使用静态工厂“命名构造函数”让你的构造函数蛋糕也吃
$newHello = Hello::createFromArray($options);

首先让构造函数按顺序包含选项。然后将这样的静态方法添加到同一个类中:

public static function createFromArray($options){

    $a = isset($options['a']) ? $options['a'] : NULL;
    $b = isset($options['b']) ? $options['b'] : NULL;
    $c = isset($options['c']) ? $options['c'] : NULL;

    return new Hello($a, $b, $c);
} 

这将使新开发人员和IDE感到高兴,因为他们仍然可以看到构建对象所需的内容。

我同意这里答案的一般态度,无论哪种方式都是可行的解决方案,取决于您的需求,哪种方式对您的应用更有利。