【发布时间】:2010-11-18 10:43:20
【问题描述】:
我在使用 PHP 进行 OOP 时让自己焕然一新,我看到了一个将函数和/或变量设置为静态的示例。何时以及为什么将变量/函数设置为静态?我使用过其他语言并且不记得曾经使用过静态,我从来没有找到它的真正目的。我知道它的作用,但为什么不直接使用变量呢?
【问题讨论】:
我在使用 PHP 进行 OOP 时让自己焕然一新,我看到了一个将函数和/或变量设置为静态的示例。何时以及为什么将变量/函数设置为静态?我使用过其他语言并且不记得曾经使用过静态,我从来没有找到它的真正目的。我知道它的作用,但为什么不直接使用变量呢?
【问题讨论】:
静态函数和变量用于访问全局范围内的变量/函数,如下所示:
echo myClass::myVariable;
echo myClass::myFunction();
当某些东西是静态的时,它可以在任何地方访问,并且与过程类型函数非常相似,除了它可以使用 self 并且包含在 classes 范围内。
class myClass{
static $myVariable = "myVar";
static function myFunction()
{
return "myFunc";
}
}
使用它的一种方法是只保留一个类的一个实例,或者一个单例方法。
class myClass
{
static $class = false;
static function get_connection()
{
if(self::$class == false)
{
self::$class = new myClass;
}
else
{
return self::$class;
}
}
private function __construct()
{
// my constructor
}
// Then create regular class functions.
}
因为它有一个私有构造函数,所以不能用new操作符实例化,所以你不得不调用myClass::get_connection()来获取一个类。该函数可以创建新类(因为它是该类的成员)。然后它将类存储在一个静态变量中,如果再次调用该函数,它将简单地返回创建的类。
最后,静态关键字用于保持事物,嗯,静态,在范围内的引用。这意味着您不希望由于当前范围而发生任何“变化”。虽然 Singleton 方法稍微扩展了这一点,但它始终保持相同的想法,即无论您处于什么范围内,您始终拥有“相同”的类。
PHP 文档
Static Keyword
Scope Resolution Operator
StackOverflow 知识
How to Avoid Using PHP Global Objects
Share Variables Between Functions in PHP Without Using Globals
Making a Global Variable Accessible For Every Function inside a Class
Global or Singleton for Database Connection
PHP Classes: when to use :: vs. -> ?
【讨论】:
=> 与静态成员有什么关系?
->
这是一个随机的,虽然fairly good description of the differences between static and instance methods。
来自帖子:
实例方法是实例方法,因为它们依赖于状态 的特定对象实例。实例方法绑定到 特定实例,因为该方法调用的行为 依赖于特定实例的状态。
当您将方法声明为静态时,您将该方法定义为 类方法。类方法适用于类,而不是任何 具体事例。类方法引发的行为确实 不依赖于特定实例的状态。事实上,一个静态的 方法不能依赖于实例的状态,因为静态方法缺乏 访问此参考。相反,类方法的行为 要么取决于所有对象在类级别共享的状态, 或者完全独立于任何状态。
如果一个方法依赖于一个对象实例的状态,它应该是一个 实例方法。如果一个方法对所有或没有一个实例是通用的 类,不依赖对象状态,应该是静态的 方法。实例方法是最常用的。然而静态 方法对于许多实用程序和工厂类非常有用 其他用途。
【讨论】:
当您想使用不绑定到实例的方法/变量时,您使用 static。这可能发生在:
与您的目的和实例没有关系(对于不允许任何其他 OOP(如 Java)的语言的工具箱很有用,但在 PHP 中没有用处)。
您想要控制对实例的访问。大多数情况下,您要处理的实例在您编写代码时并未定义,而是在执行时定义。 Singleton pattern 就是最好的例子。您可以使用静态方法作为工厂根据上下文创建对象或与其他实例共享资源。例如:静态成员可以授予对数据库层的访问权限,因此应用程序的一部分可以从任何地方访问相同的成员,并且它可以在没有冲突的情况下打开/关闭。
性能很重要,该方法将被执行很多次。在这种情况下,您将节省一些 CPU 时间,防止解释器在每次调用时将成员查找到实例。但是,如果 perfs 成为您选择此解决方案的问题,可能是时候重新考虑您的架构,或者为代码的关键部分使用与更快语言的绑定。
您有一个与某个类型相关但将应用于另一个类型的方法。将方法写入第一种类型的声明是有意义的,但将其设置为静态,因为它需要另一个类型的实例。
完美的例子是字符串解析器:
class MyObject
{
static function parse($str)
{
$obj = new MyObject();
// some parsing/setting happens here
return $obj;
}
}
// you create an object "MyObject" from a string, so it's more obvious
// to read it this way :
$new_obj = MyObject::parse("This a description of a super cool object");
【讨论】:
如果一个方法经常被调用并且做同样的事情,那么它对于缓存也非常有用,例如:
/**
* Returns true if the user is logged in through shibboleth
*
* @return boolean true on success, else false
*/
protected function is_logged_in() {
//Check shibboleth headers
if (!empty($_SERVER['HTTP_SHIB_IDENTITY_PROVIDER']) || !empty($_SERVER['Shib-Identity-Provider'])) {
if (!empty($_SERVER[$this->core->dbconfig("shib_auth", self::SHIB_AUTH_CONFIG_UID)])) {
return true;
}
}
return false;
}
这个方法会经常在我的框架中被调用,每次调用都会为我的配置 $_SERVER 键进行数据库查找
因此,当页面被处理时,我在一个页面加载中可能会调用 10 次,它将有 10 次数据库调用,但我将其更改为:
/**
* Returns true if the user is logged in through shibboleth
*
* @return boolean true on success, else false
*/
protected function is_logged_in() {
static $logged_in = null;
if($logged_in != null) {
return $logged_in;
}
//Check shibboleth headers
if (!empty($_SERVER['HTTP_SHIB_IDENTITY_PROVIDER']) || !empty($_SERVER['Shib-Identity-Provider'])) {
if (!empty($_SERVER[$this->core->dbconfig("shib_auth", self::SHIB_AUTH_CONFIG_UID)])) {
$logged_in = true;
return true;
}
}
$logged_in = false;
return false;
}
因此,如果我登录并缓存结果,它只会检查每个页面加载一次正常行为。下次它只会返回缓存的值。 我经常使用此功能以获得更高的性能。
希望这会有所帮助。
【讨论】:
访问:http://verraes.net/2014/06/when-to-use-static-methods-in-php/
静态方法只不过是命名空间的全局函数。命名空间,我想我们都同意,很棒。至于全局函数:我们一直在使用它们。 PHP 中的原生函数构成了我们的基本构建块。
【讨论】:
通常使用静态函数可以优化速度和内存,方法的范围不应该改变它应该是静态的,你可以访问对象的静态属性,方法而不启动它们,这样可以节省内存时间。
【讨论】:
如果您想与所有实例共享数据,例如当前执行时创建的实例数计数器。
【讨论】:
静态元素有许多有用的特性。
首先,它们可以在脚本中的任何位置使用(假设您可以访问该类)。这意味着您可以访问功能,而无需在对象之间传递类的实例,或者更糟的是,将实例存储在全局变量中。
其次,静态属性可用于类的每个实例,因此您可以设置希望类型的所有成员都可以使用的值。
最后,您不需要实例来访问静态属性或方法这一事实可以让您不必为了获得一个简单的函数而实例化一个对象。
【讨论】: