什么时候在php中使用静态变量/函数?


72

我正在使用PHP进行OOP更新,我看到了一个将函数和/或变量设置为静态的示例。什么时候以及为什么要将变量/函数设置为静态?我已经做过其他语言,并且真的不记得使用静态,也从未真正找到过使用它的目的。我知道它的作用,但为什么不使用变量呢?

Answers:


55

当您要使用与实例无关的方法/变量时,可以使用static。在以下情况下可能会发生这种情况:

  • 与您的目的和实例无关(对于工具箱,该工具箱的语言不允许使用类似于Java的OOP,但不允许在PHP中使用)。

  • 您要控制对实例的访问。通常,您要处理的实例在编写代码时并未定义,而是在执行时定义。的单例模式是最好的例证。您可以将静态方法用作工厂,以根据上下文创建对象或与其他实例共享资源。EG:静态成员可以授予对数据库层的访问权限,因此应用程序的一部分可以从任何地方访问同一数据库,并且它的打开/关闭没有冲突。

  • 性能很重要,该方法将执行很多次。在这种情况下,您将节省一些CPU时间,以防止解释器在每次调用时都将成员查找到实例。但是,即使perfs成为您遇到此解决方案的问题,也可能需要重新考虑您的体系结构,或者对代码的关键部分使用对更快语言的绑定。

  • 您具有与一种类型相关但将应用于另一种类型的方法。将方法写入第一种类型的声明中可能很有意义,但应将其设置为静态,因为它需要另一个类型的实例。

完美的示例是String解析器:

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");

3
在第四种情况下,您实际上将其用作一种工厂,而我将使用非静态函数。在那种情况下,使用静态函数的唯一实际需求是第二种情况,即单例及其所有实例控制表亲。
fe_lix_14年

22

静态函数和变量用于在全局范围内访问变量/函数,如下所示:

echo myClass::myVariable;
echo myClass::myFunction();

当某些东西是静态的时,它可以在任何地方访问,并且与过程类型函数非常相似,不同之处在于它可以使用self并包含在类范围中。

class myClass{
    static $myVariable = "myVar";
    static function myFunction()
    {
       return "myFunc";
    }
}

使用此方法的一种方法是仅保留一个类的实例或Singleton方法。

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()以获取类。该函数可以创建新类(因为它是该类的成员)。然后,它将类存储在静态变量中,如果再次调用该函数,它将仅返回创建的类。

最后,使用static关键字可以使范围保持静态。这意味着您不希望由于当前范围而发生任何“变化”。尽管Singleton方法对此进行了一些扩展,但仍然保持相同的想法,即无论您处于何种范围,都始终拥有“相同”类。

PHP文档
静态关键字
范围解析运算符

StackOverflow知识
如何避免使用PHP全局对象
而不在PHP中的函数之间共享变量,而无需使用全局
变量,从而使
对于数据库连接的类Global或Singleton中的每个函数都可以访问全局变量


什么是=>有静态成员呢?
Andrew Moore

晃来晃去...以为是->
泰勒·卡特

谢谢,但是由于静态变量具有相同的值,并且像变量一样不易变,当我扩展一个类并持有一个名称为静态变量的类时,如何在扩展类中更改其值呢?我也可以使用变量。两种类型都将值保留为其值,直到对象被销毁为止。

您可以更改静态变量。我从未说过它们是常数。我的意思是他们不能在范围上改变。我会澄清这一点。
泰勒·卡特

我正在使用php5.2,此代码中出现错误echo myClass :: myVariable; 它对我来说应该是$ myVariable。
标记

11

如果一个方法经常被调用并且做同样的事情,这对于缓存非常有用,例如:

/**
 * 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;
}

因此,如果我登录并缓存结果,它只会检查一次页面加载是否正常。下次它将仅返回缓存的值。我经常使用此功能以获得更高的性能。

希望这可以帮助。


7

这是对静态方法与实例方法之间差异的随机描述,尽管相当不错

从帖子:

实例方法是实例方法,因为它们依赖于特定对象实例的状态。实例方法与特定实例相关联,因为该方法调用的行为取决于该特定实例的状态。

当您将一个方法声明为静态方法时,您将该方法定义为类方法。与任何特定实例相反,类方法适用于该类。类方法所引发的行为不依赖于特定实例的状态。实际上,由于静态方法无法访问该引用,因此静态方法不能依赖实例的状态。相反,类方法的行为要么取决于所有对象在类级别共享的状态,要么完全独立于任何状态。

如果方法依赖于对象实例的状态,则应为实例方法。如果一个方法对于一个类的全部或全部实例都是通用的,并且不依赖于对象状态,则它应该是静态方法。实例方法是最常用的。但是,静态方法对于实用程序和工厂类以及许多其他用途非常有用。


3

通常,使用静态函数可以优化速度和内存,并且方法的范围不应该更改,因为它本质上应该是静态的,并且可以访问对象的静态属性,而无需启动它们的方法,因此可以节省内存。


1

静态元素具有许多有用的特性。

  1. 首先,可以从脚本中的任何位置使用它们(假设您有权访问该类)。这意味着您可以访问功能,而无需在对象之间传递类的实例,或者更糟的是,将实例存储在全局变量中。

  2. 其次,静态属性可用于类的每个实例,因此您可以设置希望对类型的所有成员可用的值。

  3. 最后,不需要实例来访问静态属性或方法的事实可以使您不必单纯地实例化对象即可获得简单功能。



0

如果您想与所有实例共享数据,例如当前执行时创建的实例数的计数器。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.