【问题标题】:Does static method in PHP have any difference with non-static method?PHP中的静态方法与非静态方法有什么区别吗?
【发布时间】:2011-01-27 04:44:51
【问题描述】:
class t {
    public function tt()
    {
        echo 1;
    }
}
t::tt();

看到了吗?非静态函数也可以在类级别调用。那么如果我在public之前添加一个static关键字有什么不同呢?

【问题讨论】:

  • 哇,它确实有效。 PHP 真是一团糟。
  • @Gumbo: PHP4 backcompat,如果你喜欢它的严格,在严格的错误上抛出异常。

标签: php static public


【解决方案1】:

Static Keyword

因为静态方法可以在没有创建对象实例的情况下调用,所以伪变量 $this 在声明为静态的方法中不可用。

不能通过对象使用箭头操作符->访问静态属性。

静态调用非静态方法会生成 E_STRICT 级别警告。

仅仅因为您可以静态调用非静态方法并不意味着您应该这样做。这是一种糟糕的形式。

【讨论】:

    【解决方案2】:

    除了,如果你尝试在你的方法中使用$this,像这样:

    class t {
        protected $a = 10;
        public function tt() {
            echo $this->a;
            echo 1;
        }
    }
    t::tt();
    

    静态调用非静态方法时会出现致命错误:

    Fatal error: Using $this when not in object context in ...\temp.php on line 11
    

    即你的例子有点太简单了,并不真正对应一个真实的案例;-)


    另请注意,您的示例应该给您一个严格的警告 (quoting):

    静态调用非静态方法 生成E_STRICT 级别警告。

    它确实做到了(至少,对于 PHP 5.3)

    Strict Standards: Non-static method t::tt() should not be called statically in ...\temp.php on line 12
    1
    

    所以:不是那么好;-)


    尽管如此,静态调用非静态方法看起来不像是任何一种好的做法(这可能是它引发严格警告的原因),因为静态方法与非静态方法的含义不同-static :静态方法不引用任何对象,而非静态方法在调用的类的实例上起作用。


    再说一遍:即使 PHP 允许你做某事(也许是出于历史原因——比如与旧版本的兼容性),这并不意味着你应该这样做!

    【讨论】:

    • 我没有收到严格的警告,php.ini 设置为error_reporting = E_ALL
    • @user :这是因为E_ALL 不包括E_STRICT -- 请参阅php.net/manual/en/errorfunc.constants.php,其中指出E_ALL“所有错误和警告,均受支持,除了PHP 中的级别 E_STRICT
    • 哦,我换成error_reporting = E_ALL & E_STRICT了,还是没有警告..PHP5.3.0
    • 这可能是因为你不需要使用E_ALL & E_STRICT,而是E_ALL | E_STRICT (即你需要E_ALL + E_STRICT -- 不确定关于在哪个版本的 PHP 中这开始引发 E_STRICT
    • not in object context 错误至少很明显。当您在发出t::tt()处于 对象上下文(属于完全不同类的某个对象的某个实例方法)中时,$this 将引用该对象,而不会发出任何警告。
    【解决方案3】:

    通常静态方法也称为类方法,而非静态方法也称为对象方法实例方法

    类方法和对象方法的区别在于,类方法只能访问类属性(静态属性),而对象方法用于访问对象属性(同一个类实例的属性)。

    静态方法和属性用于在该特定类的所有实例上共享公共数据。

    例如,您可以使用静态属性来跟踪实例的数量:

    class A {
        private static $counter = 0;
    
        public function __construct() {
            self::counter = self::counter + 1;
        }
    
        public function __destruct() {
            self::counter = self::counter - 1;
        }
    
        public static function printCounter() {
            echo "There are currently ".self::counter." instances of ".__CLASS__;
        }
    }
    
    $a1 = new A();
    $a2 = new A();
    A::printCounter();
    unset($a2);
    A::printCounter();
    

    请注意,静态属性 counter 是私有的,因此只能由类本身和该类的实例访问,而不能从外部访问。

    【讨论】:

      【解决方案4】:

      未提及的主要区别与多态行为有关。

      非静态方法,当在派生类中重新声明时,会覆盖基类方法,并允许基于调用它们的实例类型的多态行为。 静态方法并非如此


      PHP 5.3 引入了late static binding 的概念,可用于在静态继承的上下文中引用被调用的类。

      【讨论】:

        【解决方案5】:

        是的,关键区别在于声明为 static 的方法无法访问对象上下文变量 $this

        此外,当不在对象上下文中时调用非静态方法将触发E_STRICT 错误事件。启用后,该事件的默认行为是将消息输出到错误日志(或 STDERR),但它将允许程序继续运行

        此外,任何在不在对象上下文中引用$this 的尝试都会触发E_ERROR 事件。该事件的行为是将消息输出到错误日志(或 STDERR)并以状态 255 退出程序。

        例如:

        <?php
        error_reporting(-1);
        //error_reporting(E_ALL);
        
        class DualNature {
          public static function fnStatic() {
            if ( isset( $this ) ) {
              // never ever gets here
              $myValue = $this->_instanceValue;
            } else {
              // always gets here
              $myValue = self::$_staticValue;
            }
            return $myValue;
          }
        
          public function fnInstance() {
            if ( isset( $this ) ) {
              // gets here on instance (->) reference only
              $myValue = $this->_instanceValue;
            } else {
              // gets here in all other situations
              $myValue = self::$_staticValue;
            }
            return $myValue;
          }
        
          public static function fnStaticDeath() {
            return $this->_instanceValue;
          }
        
          private static $_staticValue = 'no access to $this';
          private $_instanceValue = '$this is available';
        
        }
        
        $thing = new DualNature();
        echo "==========\n";
        printf("DualNature::fnStatic(): \"%s\"\n", DualNature::fnStatic() );
        echo "==========\n";
        printf("\$thing::fnStatic(): \"%s\"\n", $thing::fnStatic() );
        echo "==========\n";
        printf("\$thing->fnStatic(): \"%s\"\n", $thing->fnStatic() );
        echo "==========\n";
        printf("DualNature::fnInstance(): \"%s\"\n", DualNature::fnInstance() );
        echo "==========\n";
        printf("\$thing::fnInstance(): \"%s\"\n", $thing::fnInstance() );
        echo "==========\n";
        printf("\$thing->fnInstance(): \"%s\"\n", $thing->fnInstance() );
        echo "==========\n";
        printf("\$thing->fnStaticDeath(): \"%s\"\n", $thing->fnStaticDeath() );
        echo "==========\n";
        echo "I'M ALIVE!!!\n";
        

        上面的输出是:

        ==========
        PHP Strict Standards:  Non-static method DualNature::fnInstance() should not be called statically in example.php on line 45
        DualNature::fnStatic(): "no access to $this"
        ==========
        $thing::fnStatic(): "no access to $this"
        ==========
        $thing->fnStatic(): "no access to $this"
        PHP Strict Standards:  Non-static method DualNature::fnInstance() should not be called statically in example.php on line 47
        ==========
        DualNature::fnInstance(): "no access to $this"
        ==========
        $thing::fnInstance(): "no access to $this"
        ==========
        $thing->fnInstance(): "$this is available"
        ==========
        PHP Fatal error:  Using $this when not in object context in example.php on line 29
        

        将错误报告级别更改为E_ALL 将抑制默认的E_STRICT 警告消息(该事件仍将传播),但对$this 的无效引用仍将导致致命错误并退出程序。

        【讨论】:

          【解决方案6】:

          除了语法和功能差异之外,还有一个重要的性能差异。

          你可以参考这个或多或少详细的comparison of static and non-static methods in PHP

          【讨论】:

            猜你喜欢
            • 2011-04-23
            • 2011-07-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-21
            • 2012-11-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多