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

Php 通过数组定义类选项是一种不好的做法吗?,php,class,settings,options,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 = '';

当我们看一看像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;
    }
}
常规方法:

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']);
这种模式有名字吗?你认为这是一种不好的做法吗


为了简单起见,我在示例中留下了验证等内容。

有好的方面,也有坏的方面

好的:

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;
    }
}
  • 不需要多个方法签名(如支持重载)
  • 与前一点保持一致:方法可以按任意顺序使用参数调用
  • 可以动态生成参数,而无需指定将出现的每个参数(例如:根据用户输入动态创建参数数组并将其传递给函数)
  • 不需要像
    setName
    setThis
    setThis
    等“样板”方法,尽管您可能仍然希望包含它们
  • 默认值可以在函数体中定义,而不是在签名中定义(jQuery经常使用这种模式。它们经常
    $。扩展
    传递给具有默认值数组的方法的选项。在您的情况下,您可以使用
    数组\ u merge()
坏的:

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;
    }
}
  • 除非您正确地宣传每个选项,否则您的类可能更难使用,因为很少有人知道支持哪些选项
  • 当您提前知道需要传递哪些参数时,这是创建参数数组的又一个步骤
  • 对于用户来说,默认值的存在并不总是显而易见的,除非提供了文档或者他们可以访问源代码

在我看来,这是一项伟大的技术。我最喜欢的方面是,您不需要提供具有不同签名的重载方法,而且签名也不是一成不变的。

我不知道名称,但我真的怀疑这是一种不好的做法,因为如果有强制选项,您通常在不声明小的o quick函数或类属性时使用此方法,它们应该在构造函数的参数列表中。然后添加带有默认值的可选选项

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

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

我不会说这是一种不好的做法,至少如果您信任数据源的话

另一种可能是根据选项数组键动态调用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);
    }
}

这种方法没有什么错,尤其是当您有很多参数需要传递给构造函数时。这还允许您在构造函数中为它们设置默认值和
array\u merge()


如果你想要这个“模式”的实例,请查看symfony框架,他们几乎在任何地方都使用它:这里是

当你给参数命名时,它被称为“命名符号”v.s.“位置符号”,其中参数必须按特定顺序排列


在PHP中,您可以传递一个“options”参数,以提供与其他语言(如Python)相同的效果,在这些语言中,您可以使用真正的命名符号。这不是一个坏的做法,但通常是在有充分理由这样做的情况下进行的(例如,在您的示例中,或者在有很多参数的情况下,它们并不都需要按任何特定的顺序设置)。

为什么不同时进行设置?拥有你的构造函数蛋糕,并与静态工厂“命名构造函数”一起享用它:
$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感到高兴,因为他们仍然可以看到构建对象所需要的东西


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

我不这么认为,它在Drupal CMS中被广泛使用!谢谢很高兴知道这么大的一个名字在使用它。IIRC,JS语法不是作为数组,而是作为一个对象的“序列化”表示(例如一直在JSON中使用)。它被称为统一构造函数:@scoates:你确定吗?PHP对“统一构造函数”有自己的定义:+½用于指出正确文档的需要+½同时提及优点和缺点。好的和坏的都排得很好!我想在其中实现它的项目有很好的文档,所以应该不会有任何问题。+1提到这是一种用不支持命名参数的语言获取命名参数的黑客行为。在接触到这种黑客之前,通常没有多少人知道命名参数。