【问题标题】:Drawbacks of static methods in PHPPHP中静态方法的缺点
【发布时间】:2010-12-16 16:57:29
【问题描述】:

在一个理论上的数据库访问类中,我发现我在类中使用了相当多的辅助函数,它们与类的实例无关(以及其他可以被操纵为与类的实例无关的函数)使用依赖注入)。

例如,我有一个函数可以获取变量中其他两个字符串之间的字符串。我一直在考虑将其移至 String_Helper 类或类似的东西。这个函数已经被静态化了。

另外,我有一个查询数据库的函数,query($sql)。连接详细信息由实例提供,但我一直在考虑将其设为静态,并使用query($sql, $connection)。然后,开发人员可以静态调用它,而根本不需要实例化数据库类。

对我来说,问题是:

  1. 这样做值得吗?像查询函数这样的函数让我想知道这是否不仅仅是我试图让一切尽可能静态,而没有任何实际需要。在什么情况下您会认为这很有用?

  2. 我知道静态函数更难测试,但如果我确保它们的代码完全无依赖(或在必要时使用依赖注入),那么它们肯定和其他所有东西一样容易测试?

  3. 目前不用担心,但如果将来我决定使用静态函数扩展类,我就不可能让当前代码使用我的扩展函数。我想到了单例,但出现了同样的问题:代码将调用Singleton_Class::getInstance(),而不是My_Extended_Singleton_Class::getInstance()。依赖注入似乎是解决此问题的唯一方法,但它可能会导致 API 更加笨拙,因为每个依赖项都必须赋予 __construct() 上的一个对象。

  4. 我有一个容器类,它静态保存某些信息,以便可以在脚本中的任何位置(全局范围)访问它们。如果我不能使用静态函数或单例,那么包含不同变量实例的类会很棒。例如可以使用Container::$objects['MyClass'] = $MyClass_object;,然后剩下的代码就可以访问Container::$objects['MyClass']。如果我扩展 MyClass 类,我可以使用 Container::$objects['MyClass'] = $MyExtendedClass_object;,而使用 Container::$objects['MyClass'] 的代码将使用 MyExtendedClass,而不是 MyClass。在我看来,这是迄今为止最好的方法,但我想知道您对此有何看法。

【问题讨论】:

    标签: php


    【解决方案1】:

    好,我来一一回答……

    1.这样做值得吗

    是和不是。将辅助函数拆分为它们自己的类是一个好主意。它严格定义了每个类的“范围”,并且您不会感到沮丧。但是,不要仅仅因为可以就将方法设为静态。查询方法可以通过管理连接让您的生活更轻松,那么您为什么要失去这种好处呢?

    2。它们更难测试

    它们并不难测试。依赖于状态的静态方法更难测试(访问静态成员变量或全局变量)。但是静态方法通常与实例方法一样容易测试(事实上,它们可以更容易,因为您无需担心实例化)。

    3.扩展类

    这是一个合理的担忧。如果您将String_Helper::foo() 放入课程本身,您会遇到问题。但是一个选项是将字符串助手的名称设置为类变量。所以你可以这样做 {$this->stringHelper}::foo() (注意,仅限 PHP 5.3)。以这种方式覆盖类,您需要做的就是更改该实例中的字符串助手类。 Lithium 框架经常这样做......

    4.全局注册表

    我会远离这个。你基本上只是让每个类都成为单例而不强制执行它。测试将是一场噩梦,因为您现在依赖于全局范围。相反,我会创建一个注册表对象并通过构造函数(依赖注入)将其传递给类。您仍然可以完成相同的事情,因为您拥有对象/类的存储,但您不再依赖于全局范围。这使测试变得更加容易。

    一般情况

    当你正在考虑做这样的事情时,我喜欢在遇到这样的问题时停下来。停下来坐下来想一想*我要解决什么实际问题?”。明确列举问题。然后拉出我们假设的解决方案,看看他们是否真的解决了这些问题。如果他们确实解决了这些问题,那么考虑未来以及这些解决方案是否从长远来看,它们确实是可维护的(无论是从错误修复的角度来看,还是就功能添加而言)。只有当你对这两个答案都满意时,你才应该考虑这样做。哦,还要记住保持简单. 编程不是要做出最复杂、最聪明或最神奇的解决方案。它是关于制作解决问题的最简单的解决方案......

    希望对你有帮助……

    祝你好运!

    【讨论】:

    • 带着这些问题,我试图解决两个问题:首先,将事物静态化是否值得以及这样做可能会带来什么问题/缺点。其次,我想找到一种最简单的方法来存储一堆对象实例,同时让它们在需要时可用。您使用注入到可能需要依赖项的任何函数的注册表的想法非常棒,因为这意味着 API 不会因为所有依赖项的参数而变得混乱,而且我仍然有办法管理任意数量的实例一个东西。谢谢你。 :)
    • @Bruno:没问题。这是与大量对象交互的一种非常标准的方式。它具有非常可测试的优点,因为您只需创建一个充满模拟对象(或仅是您的测试需要的类)的注册表并注入它。没有全局副作用,因此无需担心意外破坏任何东西。再次祝你好运……
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-23
    • 2012-03-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    相关资源
    最近更新 更多