在 PHP 中合并类成员

发布于 2024-09-06 04:46:40 字数 950 浏览 1 评论 0原文

我最近看到了 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 先生更好的代码。在保持构造函数接口干净的同时处理类成员的最佳方法是什么?

I recently came across an article by Matthew Weier O'Phinney (ZF project lead) that contains sample code similar to this:

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

    /* ... */
}

Notice how what would traditionally be four different member variables is consolidated into one array. I can see the benefit of the clean constructor (only one parameter), but I doubt IDEs will be able to do auto-completion very well on the $_data array.

One alternative I can think of is to use magic methods to have a constructor with a single parameter and the four members.

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;
    }
}

The second block of code seems better...however I doubt I can write better code than Mr. O'Phinney. What is the best way to handle class members while still keeping a clean interface to the constructor?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半衾梦 2024-09-13 04:46:40

本文中所示的 everything-in-an-array 方法背后的主要目的是让 __set 方法可以通过首先检查数组来控制设置哪些内容和不设置哪些内容。您当前的 __set 并未执行此操作,但它是一个简单的添加:

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

您希望在构造函数中执行相同的操作。

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

The big purpose behind the everything-in-an-array method as shown in the article is so that the __set method can control what gets set and what doesn't by checking the array first. Your current __set doesn't do that, but it's a simple addition:

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

You'd want to do the same thing in your constructor.

However, you're still going to have autocomplete issues. Modern IDEs that know enough to show instance methods and variables are also frequently smart enough to show or hide things in the list based on whether they're public, protected or private. Declaring everything protected will basically have the same effect as hiding them in the array, as far as the IDE is concerned. This is a major downside to using protected instance variables and __set.

时光是把杀猪刀 2024-09-13 04:46:40

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

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

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

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

也就是说,与此同时,如果您想依赖自动完成,并且不希望像 __toArray() 这样的东西有一组显式的伪属性,那么您最好只创建公共属性或设置方法,添加 phpDocs,然后没有让构造函数设置其中任何一个。只需强制使用代码通过赋值或方法调用显式配置对象即可。

It's all a trade-off. MO'P's code does indeed cause problems if you like to rely on your IDE's autocompletion. The upside is that you have a nice handy internal array that can make things like implementing a __toArray() function pretty easy.

The compromise you suggest seems silly to me. Your IDE still won't be able to help you when constructing arguments, and your magic __set() basically just makes your protected properties effectively public. You could add magic just like in Charles' answer, with the same caveats that mentions (namely, that you'll still have autocomplete issues).

I've also learned a lot from MO'P's posts, but in general it's not wise to implement things just like he does. Most of his example code is there to demonstrate a concept, and not demonstrate a practical real-world approach.

Single-argument constructors can be very useful if you have a lot of optional configuration keys. In a perfect world, perhaps there would be some extension to phpDoc so you could document valid configuration array keys for constructors.

That said, in the meantime, if you want to rely on autocomplete, and don't want an explicit set of pseudoproperties for things like __toArray(), you're better off just creating public properties or set-methods, adding phpDocs, and not having the constructor set any of them. Just force consuming code to explicitly configure the object by assignment or method calls.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文