【问题标题】:What is the difference between self::$bar and static::$bar in PHP?PHP 中的 self::$bar 和 static::$bar 有什么区别?
【发布时间】:2012-07-27 10:45:13
【问题描述】:

在下面的示例中使用self 和static 有什么区别?

class Foo
{
    protected static $bar = 1234;

    public static function instance()
    {
        echo self::$bar;
        echo "\n";
        echo static::$bar;
    }

}

Foo::instance();

产生

1234
1234

【问题讨论】:

  • @deceze:这是一个类似的问题,但不是重复的。这一个询问如何将关键字与属性一起使用,而该关键字询问如何将它们与构造函数一起使用。

标签: php oop php-5.3


【解决方案1】:

当您使用self 来指代类成员时,您指的是您在其中使用关键字的类。在这种情况下,您的Foo 类定义了一个名为$bar 的受保护静态属性。当您在 Foo 类中使用 self 来引用该属性时,您引用的是同一个类。

因此,如果您尝试在 Foo 类的其他位置使用 self::$bar,但您有一个具有不同属性值的 Bar 类,它将使用 Foo::$bar 而不是 Bar::$bar,这可能不会做你想做的:

class Foo
{
    protected static $bar = 1234;
}

class Bar extends Foo
{
    protected static $bar = 4321;
}

当您通过static调用一个方法时,您正在调用一个名为late static bindings 的功能(在PHP 5.3 中引入)。

在上述场景中,使用self 将导致Foo::$bar(1234)。 而使用static 将导致Bar::$bar (4321),因为使用static,解释器会在运行时考虑Bar 类中的重新声明。

// self
var_dump(Foo::$bar);
// (int) 1234

// static
var_dump(Bar::$bar);
// (int) 4321

您通常对方法甚至类本身使用后期静态绑定,而不是属性,因为您不经常在子类中重新声明属性;可以在以下相关问题中找到使用 static 关键字调用后期绑定构造函数的示例:New self vs. new static

但是,这并不排除将 static 与属性一起使用。

【讨论】:

  • 您可能很容易在子类中重新声明,父类可能是子类使用的默认值,除非他们重新声明。如果您在父类中,我想使用 self:: 是安全的,如果在子类中,您可以提出使用任何一个的参数,但是如果您不希望使用 self:: 也可以重新声明。
  • 转到phpfiddle.org 并运行此<?php class Foo { public static $bar = 1234; public static function a( ) { echo 'static'.static::$bar; echo 'self'.self::$bar; } } class Bar extends Foo { public static $bar = 4321; } (new Bar())->a(); ?>
  • 前两段的措辞令人困惑,有一个模棱两可的代词“它”,而且也是多余的,因为后面的段落更清楚地解释了相同的信息。我建议将前两段替换为后面以“在上述场景中”开头的段落。这样,底线,切入正题的答案就在顶部。它清晰易懂。
  • 另一种思考方式:self::$abc,在class Foo 中使用时与Foo::$abc 相同。它不会受到子类中$abc 的任何重新声明的影响。 AFAIK,使用self 的唯一原因是作为速记,以避免使用可能更长的类名Foo。 [这也意味着您可以在不更改所有这些位置的情况下更改类名-但这并不是恕我直言的原因。](PHP 的名称选择很不幸,而且似乎倒退;“静态”是可以更改的名称-与自然语言单词“static”的口语含义相反。)
【解决方案2】:

与self 通话:

class Phone
{
    protected static $number = 123;
    
    public function getNumber()
    {
        return self::$number;
    }
}
class Fax extends Phone
{
    protected static $number = 234;
}

// Displays: "123"
echo (new Fax)->getNumber();

您可以在上面看到,即使我们用 Fax 类覆盖了 $number,它仍然返回 123,因为我们已经明确要求 PHP 提供 self 变量,而后者又要求 @改为 987654328@s 变量。

现在,如果我们将self 调用与static 交换,我们将获得Faxs 覆盖值:

与static 通话:

class Phone
{
    protected static $number = 123;
    
    public function getNumber()
    {
        return static::$number;
    }
}
class Fax extends Phone
{
    protected static $number = 234;
}

// Displays: "234"
echo (new Fax)->getVar();

【讨论】:

    【解决方案3】:

    我有一个小例子显示self 和static 之间的区别。使用static:: 执行后期静态绑定,从而绑定子类中的变量值。

    class A { // Base Class
        protected static $name = 'ClassA';
        public static function getSelfName() {
            return self::$name;
        }
        public static function getStaticName() {
            return static::$name;
        }
    }
    
    class B extends A {
        protected static $name = 'ClassB';
    }
    
    echo B::getSelfName(); // ClassA
    echo B::getStaticName(); // ClassB
    

    【讨论】:

      【解决方案4】:

      也许这个自我解释的代码可以帮助你:

      class Foo 
      {
          protected static $bar = 'parent value';
      
          public static function test() 
          {
              var_dump('I am your father');
              var_dump('self:: here means '.self::$bar);
              var_dump('static:: here means '.static::$bar);
          }
      }
      
      class Bar extends Foo 
      {
          protected static $bar = 'child value';
      
          public static function test() 
          {
              parent::Test();
      
              var_dump('I am the child');
              var_dump('self:: here means '.self::$bar);
              var_dump('static:: here means '.static::$bar);
          }
      }
      
      Bar::test();
      Foo::test();
      

      这会产生以下输出(为了清楚起见,我添加了换行符):

      'I am your father' (length=16)
      'self:: here means parent value' (length=30)
      'static:: here means child value' (length=31)
      
      'I am the child' (length=14)
      'self:: here means child value' (length=29)
      'static:: here means child value' (length=31)
      
      'I am your father' (length=16)
      'self:: here means parent value' (length=30)
      'static:: here means parent value' (length=32)
      

      【讨论】:

        【解决方案5】:

        如前所述,主要区别之一是static 允许后期静态绑定。我发现的最有用的场景之一是为单例类创建基类:

        class A { // Base Class
            protected static $name = '';
            protected static function getName() {
                return static::$name;
            }
        }
        class B extends A {
            protected static $name = 'MyCustomNameB';
        }
        class C extends A {
            protected static $name = 'MyCustomNameC';
        }
        
        echo B::getName(); // MyCustomNameB
        echo C::getName(); // MyCustomNameC
        

        在基类中使用return static::$name 将返回扩展时静态附加的内容。如果您要使用return self::$name,那么B::getName() 将返回一个空字符串,因为这是在 Base 类中声明的内容。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-06-23
          • 2015-10-26
          • 1970-01-01
          • 2018-02-04
          • 2014-02-21
          • 2021-04-24
          相关资源
          最近更新 更多