在下面的示例中,使用self
和static
有什么区别?
class Foo
{
protected static $bar = 1234;
public static function instance()
{
echo self::$bar;
echo "\n";
echo static::$bar;
}
}
Foo::instance();
产生
1234
1234
在下面的示例中,使用self
和static
有什么区别?
class Foo
{
protected static $bar = 1234;
public static function instance()
{
echo self::$bar;
echo "\n";
echo static::$bar;
}
}
Foo::instance();
1234
1234
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
的可能性。
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();
- Yevgeniy Afanasyevclass Foo
中使用self::$abc
与使用Foo::$abc
是相同的。它不会受到子类中$abc
重新声明的影响。据我所知,使用self
的唯一原因是为了缩写,避免使用可能更长的类名Foo
。[这也意味着您可以更改类名而无需更改所有这些位置 - 但在我看来这并不是一个很好的理由。](PHP选择的名称不幸,并且似乎是反向的;“static”是可以更改的 - 这与自然语言词“static”的口语含义相反。) - ToolmakerSteve我有一个小例子,展示了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 A::getSelfName(); // ClassA
echo A::getStaticName(); // ClassA
echo B::getSelfName(); // ClassA
echo B::getStaticName(); // ClassB
使用 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
,getNumber()
仍然返回123
。这是因为我们要求PHP给我们定义它的变量 - 这将返回Phone
的变量。如果我们用static
替换self
调用,我们将获得Fax
覆盖的值:
使用static
调用: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();
如上所述,其中一个主要区别在于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
在 Base 类中使用 return static::$name
会返回静态扩展时附加的内容。如果您使用 return self::$name
,那么 B::getName()
将返回一个空字符串,因为在 Base 类中声明了一个空字符串。
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)
self::
和static::
都指向父类中的静态属性/函数。但是,self::
从定义函数的类中获取内容,而static::
从执行函数的类中获取内容。
class Parent
{
static $best_afternoon = ' take a nap.';
static $opinion_of_plan = ' enjoy';
$name;
function __construct($name){$this->name = $name;}
function plan()
{
echo $this->name . ' will' . self::$best_afternoon;
}
function nap()
{
echo $this->name . ' will' . static::$opinion_of_plan . ' it.';
}
}
class Child extends Parent
{
static $best_afternoon = ' run around.';
static $opinion_of_plan = ' dislike';
}
$mother = new Parent('Alice');
$son = new Child('Ben');
$mother->plan(); //> "Alice will take a nap."
$son->plan(); //> "Ben will take a nap."
$mother->nap(); //> "Alice will enjoy it."
$son->nap(); //> "Ben will dislike it."
$son->plan()
可能会返回完全不同的结果。当然,直接问本仍然会返回Child类中覆盖的值的最佳下午活动。echo $mother::$best_afternoon; //> " take a nap."
echo $son::$best_afternoon; //> " run around."