PHP 中 self::$bar 和 static::$bar 有什么区别?

问题描述 投票:0回答:6

在下面的示例中使用

self
static
有什么区别?

class Foo
{
    protected static $bar = 1234;

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

}

Foo::instance();

产生

1234
1234
php oop php-5.3
6个回答
256
投票

当您使用

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

因此,如果您尝试在

self::$bar
类中的其他位置使用
Foo
,但您的
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

但是,这并不排除将

static
与属性一起使用。


50
投票

我有一个小例子显示

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

32
投票

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

您可以在上面看到,即使我们已经用

$number
类覆盖了
Fax
getNumber()
仍然返回
123

这是因为我们要求 PHP 给我们定义它的变量 -- 这将返回

Phone
s 变量。

如果我们将

self
调用与
static
交换,我们将得到
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();

12
投票

如前所述,主要区别之一是

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()
将返回一个空字符串,因为这是在基类中声明的。


12
投票

也许这个不言自明的代码可以帮助您:

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)

0
投票

精简版

self::
static::
都引用父类中的静态属性/函数。但是,当
self::
定义函数的类中获取某些内容时,
static::
执行函数的类中获取某些内容。

示例

class Parent
{
   function __construct($name){}

   static $best_afternoon = ' take a nap.';
   static $opinion = ' enjoy';

   function plan()
   {
      echo $this->name . ' will' .  self::$activity;
   }
   function nap()
   {
      echo $this->name . ' will' . static::$opinion . ' it.';
   }
}
class Child extends Parent
{
   static $best_afternoon = ' run around.';
   static $opinion = ' dislike';
}

每个

Child
都从
plan()
类继承
nap()
Parent
函数,并覆盖
$best_afternoon
$opinion
。但是
plan()
即使在继承时也保留其原始上下文,因为它使用
self::
而不是
static::

$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."

当然,如果孩子们有自己的

plan()
,调用
$son->plan()
可能会返回完全不同的东西。当然,直接询问 Ben
Child::$best_afternoon
是什么仍然会返回被覆盖的
Child
值(“到处乱跑”)。

© www.soinside.com 2019 - 2024. All rights reserved.