静态方法:考虑到PHP 5.3后期静态绑定,它们仍然不好吗?

时间:2011-05-17 19:06:51

标签: php oop design-patterns dependency-injection singleton

如果你搜索静态方法不好的原因,你发现它的第一件事是因为你在单元测试时不能覆盖它。

考虑到PHP 5.3,你可以通过引入static::做任何你想做的事吗?

添加:

http://sebastian-bergmann.de/archives/883-Stubbing-and-Mocking-Static-Methods.html

注意他甚至解释了如何在没有任何测试问题的情况下使用单例:

3 个答案:

答案 0 :(得分:12)

如果你有一个静态成员函数,它通常可以是一个自由函数。通常的反应是编码器选择静态成员函数只是因为“一切都必须在一个对象中”的神话。

这就是人们劝阻他们的原因。

并且,因为这不是一个非常令人信服的论点,那些人指的是单元测试。不确定他们现在会做什么。

答案 1 :(得分:10)

静态方法本身并不坏。有时某些操作对于要求特定对象没有意义。例如,像平方根这样的函数更有意义是静态的。

Math::sqrRoot(5);

而不是必须实例化一个Math'对象',然后调用该函数。

$math = new Math();
$result = $math->sqrRoot(5);

答案 2 :(得分:6)

更难以测试是一个原因,但不是唯一的原因。静态方法提供全局访问,而全局访问则很糟糕。

当然,您会发现对象的另一个全局访问权限正在创建一个具有“新”的对象。必须在某处创建对象,因此我们无法消除它(尽管最小化它是一个好主意)。作为对类的全局访问的静态方法很糟糕,除非通过更高级别的编程替换“new”:

$user = new User();
$user->setPointsTo(100);

// vs

$user = User::with100StartingPoints();

在这种情况下,我创建的代码更具可读性,同时不会滥用全局访问(无论如何都需要调用'new')。

编辑:让我举一个例子,静态方法'可以'可测试性的死亡(注意上面的例子中你甚至不需要模拟静态方法但可以轻松测试新的和静态的方法产生相同的结果)。让我们使用您的记录器示例:

class Logger {
    public static function log($text) { // etc }
}

class AccessControl {
    public function isAllowed(User $user, $action) {
      // do stuff, determine if $allowed
      if (!$allowed) {
          Logger::log('user X was not allowed to do Y');
      }
      // do stuff
    }
}

由于对Logger :: log的全局调用,我们无法干净地测试此方法。这将取决于Logger类的正确工作。