何时在PHP中使用静态修饰符?

35

最近我在做一些代码审查时,发现有很多类里面都有大量的静态方法...但我似乎无法理解为什么?因此我的问题是:

在PHP中使用静态方法的最佳实践是什么?

什么情况下应该使用它们,什么情况下不应该使用它们?

运行时如何处理静态方法的具体差异?它们是否影响性能或内存占用?


1
到目前为止还没有人回答最后一个问题 -- "它们会影响性能或者内存占用吗?" 静态变量通常在Java中是不被鼓励使用的。不确定这个对于解释性语言如PHP也是适用的。 - powerboy
如果您正在进行面向对象编程(正如您所标记的那样),则永远不要这样做:https://dev59.com/F2435IYBdhLWcg3w3EIi#23386464 - Alejandro Moreno
8个回答

23

最近我在做一些代码审查,发现有一些类中有大量的静态方法......但我似乎无法理解为什么

PHP 5.3之前没有命名空间,因此所有的函数/变量都将处于全局作用域,除非它们属于某个类。将它们置于类中作为静态成员是解决没有命名空间的一种方法(这可能就是你看到它们数量“显著”的原因)。

通常,它们被用于在个别对象中不太有用但在类级别上有一定用途的函数(如其他答案中所说)。


2
将相关函数作为静态函数存储在类中,还可以探索PHP的一个强大特性:按需自动加载类。它允许您编写代码而不必担心进行适当的包含,并且无需包含可能不总是使用的内容。只需调用您的静态方法,__autoload()就能够实现其魔力。清洁、优化和功能强大的编码。即使是名称空间也没有达到这个水平。 - Havenard

7
最佳实践是尽可能避免使用它们,因为它们会影响可测试性和可维护性。以下两篇文章详细阐述了这个问题: 澄清一下:这个问题似乎存在很多误解。缺乏依赖注入才是真正的问题。直接调用静态方法只是陷入这个陷阱最常见的一种方式之一。

3
我之前看过这些争论,但它们并不令人信服。使静态方法具有可测试性的方法是不产生副作用;这类方法是所有方法中最易于测试的;你给它们输入,它们返回输出,就这样。对一个类参数的强依赖也没有意义;将相关的静态方法组合在一起是整个过程的重点。 - Robert Harvey
1
你没有解决这两个链接的关键问题——依赖性。能够覆盖所依赖的函数对于测试至关重要。公平地说,使用静态函数(例如,将函数依赖项作为参数传递)也是可能的。然而,在PHP中惯用的解决方案是使用一个非静态函数,可以被子类覆盖。请参阅http://kunststube.net/static/以获取更多详细信息。 - Russell Davis
1
正确编写的静态函数不具有任何依赖项,除了直接传递到函数中的内容。测试函数,确保其具有预期行为,然后按原样在所有其他测试中使用它。您链接提供的示例是误用,因为多次调用函数可能每次产生不同的结果。我不知道;我只是看不出使用“static”方法的好处。 - Robert Harvey
1
为了编写字典的测试,我需要知道静态实现的细节以编写我的测试。——游戏结束。正确使用静态方法不需要了解其内部实现。我认为大多数抱怨使用static方法进行测试困难的人通常只是错误地使用static方法。更多信息请参见:http://programmers.stackexchange.com/a/5963/1204 - Robert Harvey
2
同意。仔细看这段代码,它也可以将this.hasher设置为静态哈希函数,这同样可以解决可测试性问题。 - Russell Davis
显示剩余2条评论

5

静态方法用于:

  • 与给定类的所有对象集合相关的函数(例如singleton模式
  • 与任何内容无关,但必须放在一个类下面因为面向对象编程(例如实用类)

4

静态方法不需要实例(也可以返回一个实例),与全局函数类似,但它是放在类命名空间中的(因此避免了与其他函数的冲突)并且可以访问类的私有成员。

因此,只要您对函数的这些属性感兴趣,就可以使用它。


3

在使用静态方法方面,与PHP无关。

可以直接在类上调用静态方法 - 不需要已实例化的对象。

因此,它们主要用于与类功能相关的方法,但不需要现有实例就可为其他代码提供帮助的情况。

一个常见的例子是自定义比较方法,可以将其传递给uasort()函数,以对该类类型的对象数组进行排序。


2

为了获得更好的性能,您可以使用静态方法。不需要为每个使用您的Web应用程序的用户创建对象,创建具有多个方法和属性的对象会更慢,并且需要更多的系统资源。


1

你不需要创建类的实例来使用其静态方法。


1

每当一个方法不需要类的实例并且可能需要与类的任何实例分开使用时,它应该是静态的,前提是可以安全地依赖于它。类的实例可以作为参数传递给静态方法,但我认为这是一种不好的做法,因为它可能会创建难以调试的代码。

滥用静态方法肯定会创建非常难以测试的代码。如果静态方法需要在单元测试中与非静态方法一起测试,则它不应该是静态的。然而,如果您可以独立于任何类实例完全测试所有可能的边缘情况的方法,则无需担心单元测试,因为静态方法可以有自己独立的单元测试。

另一件您应该考虑的事情是依赖注入。静态方法可以通过将它们放在单独的命名空间中来进行覆盖。要覆盖静态方法,只需将命名空间切换到具有覆盖静态方法的命名空间即可。但是,如果您需要这样做,那么您更有可能滥用静态方法。

如果一个方法当前看起来很适合是静态的,但在未来的修改后可能不再适合,则最好将其设置为非静态的。它需要被依赖而不会导致错误。滥用静态方法肯定会导致依赖关系的噩梦。

许多人认为避免使用静态方法是最佳实践,然而我不同意这种观点,因为每种编程语言都有大量内置的静态函数和关键字。我们不会因为它们是静态的就重新编写它们。我们只需要放心地使用它们,如果需要,我们可以非常容易地测试它们是否存在任何可能的边缘情况。

@peterh,我不明白中国文化大革命与我的回答有什么关系。你是不是在错误的地方发表了评论? - Dan Bray
在其他编程语言中,static 不再使用。相反,库/框架在初始化时分配一个准静态的东西(可能是进程启动,但也可以是用户第一次登录等)。这里有点难以直接与他人沟通。您建议我在安全SE上更改我的帖子。我对这些框架-语言的问题是它们需要难以想象的大量RAM和初始化时间,我认为最好摆脱它们。 - peterh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接