4

我最近看到Matthew Weier O'Phinney(ZF 项目负责人)的一篇文章,其中包含与此类似的示例代码:

class User
{
    protected $_data = array(
        'username' => null,
        'email'    => null,
        'fullname' => '',
        'role'     => 'guest',
    );

    /* ... */
}

注意传统上四个不同的成员变量是如何合并到一个数组中的。我可以看到干净的构造函数(只有一个参数)的好处,但我怀疑 IDE 是否能够很好地在$_data数组上进行自动完成。

我能想到的另一种选择是使用魔术方法来创建一个带有单个参数四个成员的构造函数。

class User
{
    protected $_username = null;
    protected $_email = null;
    protected $_fullname = '';
    protected $_role = 'guest';

    public function __construct($data)
    {
        foreach ($data as $key => $value) {
            $this->$key = $value;
        }
    }

    public function __set($name, $value) {
        $member = "_$name";
        $this->$member = $value;
    }
}

第二个代码块似乎更好......但是我怀疑我能写出比 O'Phinney 先生更好的代码。处理类成员的最佳方式是什么,同时仍保持与构造函数的干净接口?

4

2 回答 2

2

如文章中所示,一切都在数组中的方法背后的重要目的是,该__set方法可以通过首先检查数组来控制设置的内容和不设置的内容。您的当前__set没有这样做,但这是一个简单的补充:

public function __set($name, $value) {
    $member = "_$name";
    if(property_exists($member, $this)) // <- New magic.
        $this->$member = $value;
}

你想在你的构造函数中做同样的事情。

但是,您仍然会遇到自动完成问题。现代 IDE 足够了解以显示实例方法和变量,通常也足够聪明,可以根据它们是公共的、受保护的还是私有的来显示或隐藏列表中的事物。就IDE而言,声明所有受保护的内容基本上与将它们隐藏在数组中具有相同的效果。这是使用受保护的实例变量和__set.

于 2010-06-22T02:50:16.247 回答
1

这都是一个权衡。如果您喜欢依赖 IDE 的自动完成功能,MO'P 的代码确实会引起问题。好处是你有一个非常方便的内部数组,它可以使实现 __toArray() 函数之类的事情变得非常容易。

你建议的妥协对我来说似乎很愚蠢。在构造参数时,您的 IDE 仍然无法为您提供帮助,而您的魔法 __set() 基本上只是让您的受保护属性有效地公开。您可以像在查尔斯的回答中一样添加魔法,并注意提到的相同警告(即,您仍然会遇到自动完成问题)。

我也从 MO'P 的帖子中学到了很多东西,但总的来说,像他那样实施事情并不明智。他的大部分示例代码都是为了演示一个概念,而不是演示实际的现实世界方法。

如果您有很多可选的配置键,单参数构造函数会非常有用。在一个完美的世界里,也许 phpDoc 会有一些扩展,这样你就可以为构造函数记录有效的配置数组键。

也就是说,与此同时,如果您想依赖自动完成功能,并且不想为 __toArray() 之类的东西提供一组明确的伪属性,那么您最好只创建公共属性或 set-methods,添加 phpDocs 和没有构造函数设置它们中的任何一个。只需强制使用代码通过赋值或方法调用显式配置对象。

于 2010-06-22T03:00:17.430 回答