静态方法得到 - 这是不好的做法?

时间:2011-03-02 12:46:18

标签: php oop static-methods

与同事讨论过这是不好的做法。现在我在网上找不到这个例子。

我们有很多数据库对象映射器并且像它这样调用它的函数

(示例) - setId方法获取数据库中的行并将其设置为预定义的属性

class Person {

    public static function get($id) {
        $object = new Person;
        $object->setId($id);
        return $object;
    }
}

像这样使用它我们可以使用这样的简单结构:(我们从例如一个帖子得到id)

$person = Person::get($id);

而不是

$person = new Person;
$person->setId($id);

现在,我的直觉告诉我这是不好的做法。但我无法解释。也许有人在这里可以解释为什么这是,或者不是不好的做法

以下是我们如何使用它的一些其他示例。我们主要用它来吸气。 (只是名称,而不是代码。几乎所有这些都只运行一个查询,它可以返回1个对象,然后使用结果的id来使用setId方法)

class CatalogArticle {
   public static function get($id) { }
   public static function getByArticlenumber($articlenumber) {} //$articlenumber is unique in the database
   public static function getRandom() {} //Runs a query returning a random row
}

5 个答案:

答案 0 :(得分:14)

这不是可怕的 persay。它是Factory Method设计模式的实现。原则上它一点也不差。

但是,在你的具体例子中,它并没有真正做任何重要的事情,所以我不确定是否有必要。您可以通过将(可能是可选的)参数添加到id的构造函数来消除这种需要。然后任何人都可以调用$foo = new Person($id);而不是需要一个明确的工厂。

但是如果实例化很复杂,或者您希望能够构建几个只能由逻辑确定的不同人员类型,那么工厂方法可能会更好。例如,假设您需要确定某个参数实例化的人员类型。然后,Person上的工厂方法是合适的。该方法将确定要加载的“类型”,然后实例化该类。

一般来说静态很难测试,并且不允许像实例那样进行多态变更。它们还在代码中的类之间创建硬依赖关系。它们不是可怕的,但如果你想使用它,你应该考虑它。一个选项是使用BuilderAbstract Factory。这样,您可以创建构建器/工厂的实例,然后让该实例确定如何实例化生成的类...

另一个注意事项。我会将该方法从Person::get()重命名为更符合语义的方法。也许是Person::getInstance()或其他合适的东西。

答案 1 :(得分:5)

这篇博文应该告诉你为什么人们不喜欢静态方法比我更好:

http://kore-nordmann.de/blog/0103_static_considered_harmful.html

关于您当前的代码段最让我印象深刻的问题:是否允许某人没有ID?

我觉得如果它代表一个真人,那应该是一个构造函数参数。如果您使用该类创建可能无效的新人。


两次通话之间的差异很小。两者都“创建”一个Person类并设置Id,这样当你遇到“硬连线依赖”时你就不会赢得/失去任何东西。

优势仅显示当您希望能够将Person传递到另一个对象并且该对象需要更改ID时(例如,博客文章应该比我在此更好地解释)。

答案 2 :(得分:2)

我只是添加到edorian的帖子,但我过去使用过静态get方法,其中有一个缓存引擎,并且(例如)我可能在memcache中有一个给定的Person对象,并且而不是从缓存中检索它而不是去数据库。

例如:

class Person {

    public static function get($id) {

        if(Cache::contains("Person", $id))
        {
           return Cache::get("Person", $id);
        }
        else
        {           
            //fictional get_person_from_database, basically
            //getting an instance of Person from a database
            $object = get_person_from_database($id);
        }
        return $object;
    }

}

通过这种方式,所有缓存处理都由相关的类完成,而不是调用者让人调用不必担心缓存。

答案 3 :(得分:1)

长话短说,是的,他们是不好的做法:

除了一切之外,一个很好的理由是你应该'测试你的代码。静态方法会导致问题,所以你有充分的理由:

  • 如果您想遵循良好做法,请测试您的代码
  • Ergo,如果静态导致测试问题,静态阻止编写测试,以防止遵循良好实践: - )

答案 4 :(得分:0)

时间随时间变化。

万一测试遇到问题,可以使用AspectMock库 https://github.com/Codeception/AspectMock

任何方式静态都没有那么糟糕。要使用静态,您应该只知道自己在做什么以及为什么。如果仅将静态作为快速解决方案放置,那么在99%的变化中这是个坏主意。在1%的时间内,它仍然是一个糟糕的解决方案,但是它可以在需要时为您提供时间。

相关问题