【问题标题】:php static functions vs instance functions, basicsphp 静态函数 vs 实例函数,基础
【发布时间】:2011-09-16 22:33:02
【问题描述】:

我正在尝试了解何时应该使用静态函数,但我很难找到答案。我正在创建一个类User,它与一个类Group 相关。如果我有一个用户 id 并且我想从中获取一个用户对象,那么做类似的事情会更好

$existingUser = User::get($userId); 

类是这样定义的

class User()
{ 
    public static function get($id){
        $user = new User();
        return $user->findById($id);
    }
    public function findById($id) {
        //find and populate user object
    }
}

$existingUser=new User();
$existingUser->findById($userId);

类是这样定义的

class User()
{ 
    public function findById($id) {
        //find and populate user object
    }
}

如果我要编写一个基于用户 ID 返回一组 Group 对象的函数会怎样?

class User()
{ 
    //stuff
    $groupArray = Group::getAllByUserId($this->getId())
    //stuff
}

class User()
{ 
    //stuff
    $group = new Group();
    $groupArray = $group->findAllByUserId($this->getId());
    //stuff
}

第二种方法创建一个从未使用过的空组对象。有关系吗? 我误解了静态的概念吗?我知道不必实例化一个类很有用,所以如果函数无论如何都要实例化一个类,那会破坏目的吗?如果是这样,什么时候使用静态函数的例子是什么?

在这个过于简化的例子中我还应该考虑什么?

【问题讨论】:

标签: php oop static static-functions


【解决方案1】:

在上面显示的情况下,您不需要静态函数。

静态函数实际上只是具有命名空间的全局函数。

当需要控制应用程序的全局状态,或者如果函数的多个副本导致结果不一致时,请使用它们。

回调有时需要是静态的,尤其是当它们作为字符串传递时。

【讨论】:

  • "回调有时需要是静态的,尤其是当它们作为字符串传递时。" - 不,你可以使用array($object, $method)
【解决方案2】:

我正在尝试了解何时应该使用静态函数

哦,很简单:从不

要了解它,请阅读:
http://www.objectmentor.com/resources/articles/ocp.pdf
http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/

【讨论】:

  • -1 永远不会过于简单化。当然,通过依赖注入处理数据库更好,但是大量的库框架等使用静态方法。不幸的是,在现实世界中,您无法从头开始构建所有代码。
  • @Byron Whitlock 我们谈论的是编写我们自己的代码,而不是重构 3-d 派对库。并且“大量框架使用静态”不是论据。写烂代码不读书比读书写好代码容易得多。
  • 谢谢,这让我了解了一个全新的概念(测试驱动开发)。我现在对我的所有代码都使用单元测试,并尽可能避免使用静态方法。
【解决方案3】:

我发现一个好的经验法则是“如果我没有 [class-name],我是否希望能够调用 [method-name]?”

如果我没有用户,我是否可以调用 findByID? 可能不是。这是我遇到的例外之一; “加载”或“保存”方法有时是静态的。

何时使用非静态方法的一个完美示例是(大多数方法中的)数据库类 - 在尝试对其运行查询之前,您应该始终拥有一个数据库对象。

何时使用静态方法的一个例子是“帮助”类,它本质上是一组方便的函数。假设您有一些方法可以帮助您输出 HTML,您可能有 HTML::image()HTML::url()HTML::script()。在这些上,您不需要 HTML 对象来创建图像、URL 等。

至于停止正在创建的对象的多个副本(使用静态方法的一个参数),您应该改用单例模式(谷歌它)来确保只存在一个对象的副本。

【讨论】:

  • HTML::image()HTML::url()HTML::script() 这样的函数是不应该使用静态方法的最佳示例之一。这没有任何意义。如果你关心命名空间并调用\HTML\img()\HTML\script(),你会好很多。任何使用此类的“框架”都应该像黑死病一样被避免。
  • @tereško:您并不总是可以在 >=PHP5.3 服务器上进行部署。
  • @phant0m 然后打电话给他们html_img() .. 有什么区别?只是不要在编写过程代码时假装自己在“做 OOP”。
  • @tereško: 你能解释一下为什么像 HTML::image(), HTML::url()... 这样的函数是你不应该使用静态方法的最好例子之一吗???那么 Filter::isEmail($email) 呢?为什么要创建命名空间,而不是'静态方法更用户友好?!
  • @MarcoDemaio,你能回答吗,Filter 类对象的职责是什么?您的示例破坏了 SRP ,因此它不是面向对象编程的示例。如果您想编写程序代码,请编写它。不要假装它是 OOP。
【解决方案4】:

您可能应该在 Active Record 与数据映射器上查看这个问题:

https://stackoverflow.com/questions/2169832/data-mapper-vs-active-record

从这个问题中可以看出,在大多数情况下,类上用于加载/保存的静态方法并不是该类的真正核心功能。此外,在大多数情况下,存储和加载是一种与类对象分离的抽象概念。

“用户”是数据存储和检索对象吗?在大多数情况下,不,它是您系统中代表的具有各种属性和功能的人。当您开始将该对象的持久性绑定到该对象中时,您会破坏封装并使代码的维护变得更加困难。如果下周你想从内存缓存中加载你的用户怎么办?这与用户是否可以拥有某些属性或功能几乎没有关系。

【讨论】:

  • 我想我正在使用数据映射器(此示例中未显示),但我不明白这有什么关系
  • Data Mapper 意味着您有第二个具有静态函数的外部类,即 UserMapper,其中包含查找和加载用户的静态方法。有时使用的类比是,如果您正在制造汽车,您不会在汽车中放置发动机工厂来获取发动机。您会去外部发动机工厂并要求购买新发动机。
  • “Data Mapper 暗示你有第二个带有静态函数的外部类” - 这是错误的认识。
  • martinfowler.com/eaaCatalog/dataMapper.html -- 它们不一定是静态的,我的输入错误。我经常将它们视为静态实现,但我也看到很多实例化的映射器类
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 2010-10-28
  • 2013-10-23
  • 1970-01-01
  • 2011-04-19
  • 1970-01-01
相关资源
最近更新 更多