关于oop:PHP构造函数接受一个数组而不是多个参数

PHP constructor take in one array instead of multiple params

让所有类构造函数接受一个参数数组,而不是多个参数,这是一个好主意吗?

例如,

1
2
3
4
5
6
7
8
9
10
11
12
13
class A {

private $id;
private $name;

__construct($arr) {
    foreach ($arr as $key => $val) {
        $this->$key = $val;
    }

}

}

而不是

1
2
3
4
5
6
7
8
9
10
11
12
class B {

private $id;
private $name;

__construct($id, $name) {
   $this->id = $id;
   $this->name = $name;

}

}

这将消除记住参数顺序的需要,并且每次添加新参数时都需要键入"$this->key=$val"。这种方法有什么缺点吗?


虽然这确实是一种观点,但我并不认为这样做是一种很好的做法。您将失去在函数/方法边界强制执行适当的调用签名的能力。您将失去为传递的参数强制类型的能力(或者为支持此功能的IDE提供类型提示)。所以这样的事情不能强制执行:

1
function foo ($bar, PDO $pdo_obj) {}

您还将失去提供以下默认参数值的能力:

1
function foo ($bar, $optional = 'default') {}

您还可能使该方法暴露于意外行为。例如,如果其中一个采用您在示例中建议的方法。如何防止调用者传递可能耗尽内存分配的任意长度的数组?

实际上,你甚至不应该设计一个可以接受超过3或4个参数的函数,所以我不知道你在这里真正得到的是什么,除了能够以未定义的顺序得到"参数"。这种"灵活性"的代价是,然后需要围绕任何参数创建数组包装器,否则将直接传递给函数/方法。

最后,我要说明的是,您建议的方法并不是PHP中的典型编码实践。因此,如果您曾经期望其他人使用您的代码,那么这种方法可能会让他们感到困惑,因为它不是通常会遇到的事情。


缺点是你根本没有暗示的类型。如果您有单独的参数,并且使用了适当的IDE(如netbeans或phpsorm),那么您将有可用的工具来帮助您记住参数的顺序。如果您只是传入一个数组,那么您就没有这些信息,没有类型提示,也没有具体的错误,以防忘记添加参数或稍后添加参数,而忘记更改对构造函数的某个调用。

所以我选择不这样做,尽管在这个问题上意见可能有所不同。在JavaScript中,这似乎更常见。jquery和其他库很大程度上依赖于这种机制,但是对于PHP,我不会,因为上面描述的原因。


缺点是您更可能忘记设置特定的参数。不过,有很多方法可以控制这种情况。我所知道的最好的方法是创建一个异常类,如MissingParameterException,并为任何缺少的必需参数抛出该类的异常。您还可以对错误类型的内容进行类型检查和抛出异常。

我会加一张这样的支票:

1
2
3
if(property_exists($this, $key)) {
    $this->$key = $val;
}

为了防止随机未知属性的意外设置。

我担心的是,您的对象在构造函数中需要如此多的参数,以至于您无法保持它们的直线性。请查看有多少构造函数参数太多,无法讨论不同的设计模式。


我认为这是不好的。

客观地说,我认为这会使任何维护您的代码库的人更难遵循代码,因为它是非常规的。此外,我认为当您消除了记住参数顺序的需要时,您更可能引入错误,因为您在代码中添加了一层模糊。

诚然,我认为这是一个糟糕的部分原因是因为我第一次学习Java编程,对Java设计模式有偏见,认为一致性很重要。