在PHP中,self::$bar和static::$bar之间有什么区别?
在PHP中,self::$bar和static::$bar之间有什么区别?
在下面的示例中,使用self
和static
有什么区别?\n
class Foo { protected static $bar = 1234; public static function instance() { echo self::$bar; echo "\n"; echo static::$bar; } } Foo::instance();
\n
输出结果如下:
\n
1234 1234
\n使用self
关键字时,引用的是当前类的静态属性$bar
。使用static
关键字时,引用的是调用该方法的类的静态属性$bar
。在这个例子中,Foo::instance()
是由类Foo
调用的,所以无论是使用self
还是static
,都引用的是Foo
类的静态属性$bar
,所以输出结果相同。
在上面的代码示例中,我们可以看到,尽管我们在Fax
类中覆盖了$number
变量,但getNumber()
仍然返回123
。这是因为我们要求PHP返回变量在哪里定义的,它将返回Phone
类的变量。
如果我们将self
调用换成static
,我们将得到Fax
类的覆盖值:
class Phone { protected static $number = 123; public function getNumber() { // return self::$number; return static::$number; } }
class Fax extends Phone { protected static $number = 234; } // Displays: "234" echo (new Fax)->getNumber();
这是一个非常直观和不会引起混淆的示例。
问题的原因是使用self
关键字时,PHP将返回变量在哪个类中定义的,而不是在哪个类中调用的。因此,self::$number
返回的是Phone
类中的$number
变量,而不是Fax
类中的。
为了解决这个问题,我们可以使用static
关键字。使用static::$number
将返回在当前类中定义的$number
变量,而不管是在父类还是子类中定义的。
这种区别在继承和多态的情况下特别重要。通过使用static
关键字,我们可以确保在子类中覆盖父类的变量时,调用正确的变量值。
这个问题的出现是因为在PHP中,使用self::$bar
和static::$bar
时,会有不同的结果。以下是一个简单的示例来展示它们之间的区别:
class A { // 基类 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 A::getSelfName(); // 输出:ClassA echo A::getStaticName(); // 输出:ClassA echo B::getSelfName(); // 输出:ClassA echo B::getStaticName(); // 输出:ClassB
在上面的示例中,类A
定义了一个静态属性$name
,并且有两个静态方法getSelfName()
和getStaticName()
。其中getSelfName()
使用self::$name
来访问静态属性,而getStaticName()
使用static::$name
来访问静态属性。
当我们调用A::getSelfName()
时,它返回的是ClassA
,因为self::$name
指向的是A
类自身的静态属性。
同样地,当我们调用A::getStaticName()
时,它也返回的是ClassA
。这是因为static::$name
在这里也指向A
类自身的静态属性。
然而,当我们调用B::getSelfName()
时,它仍然返回的是ClassA
,而不是ClassB
。这是因为self::$name
指向的是定义这个属性的类自身,即A
类。
但是,当我们调用B::getStaticName()
时,它返回的是ClassB
。这是因为static::$name
在这里指向的是调用这个方法的类,即B
类。
为了解决这个问题,我们可以使用static
关键字来实现后期静态绑定。这样,static::$bar
将根据调用方法的类来确定属性的值。这样,我们就可以在子类中正确地访问静态属性。
总结起来,self::$bar
始终指向定义这个属性的类自身,而static::$bar
会根据调用方法的类来确定属性的值。这种区别在使用继承和静态属性时很重要,可以确保在子类中正确访问静态属性。
在PHP中,使用`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`调用一个方法时,你正在调用一个被称为“后期静态绑定”的特性(在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](https://stackoverflow.com/questions/5197300)
然而,这并不排除使用`static`来处理属性的可能性。在子类中很容易重新声明父类的属性,父类的属性可能是子类使用的默认值,除非它们重新声明。如果你在父类中,我猜使用`self`是安全的;如果在子类中,你可以找到一个使用任何一个的理由,但是如果你不希望重新声明,`self`也可以工作。
去[phpfiddle.org](http://phpfiddle.org/)运行下面的代码:
a(); ?>
前两段文字表达不清晰,存在一个含糊不清的代词"it",而且也有冗余的部分,因为后面的段落更清楚地解释了相同的信息。建议用后面以"In the above scenario"开头的段落替换前两个段落,这样底线的简洁答案就在最前面。这样更清晰和易于理解。
另一种思考方式:`self::$abc`在`class Foo`内部使用时,等同于`Foo::$abc`。它不会受到子类中`$abc`的重新声明的影响。据我所知,使用`self`的唯一理由是作为一种简写,避免使用可能更长的类名`Foo`。[它也意味着你可以在不改变所有使用的地方的情况下更改类名 - 但在我看来,这并不是一个很好的理由。](PHP的命名选择不太幸运,似乎是相反的;"static"可以改变 - 这与自然语言中"static"的意思相反。)