self、static 和 $this 的区别
为了更好地理解 self、static 和 $this 的区别,先来看一个示例。
<?php class A { protected $name = 'A'; static $alias = 'a'; const HASH = 'md5'; public function dd() { echo $this->name; echo '--'; echo static::$alias; echo '--'; // 后期静态绑定 echo static::HASH; echo '--'; // 后期静态绑定 echo self::$alias; echo '--'; echo self::HASH; echo '--'; var_dump(new self); echo '--'; var_dump($this); echo '--'; var_dump(new static); echo '<br>'; // 后期静态绑定 } public static function who() { echo __CLASS__; echo ' [ This is A ]'; echo '<br>'; } public static function test() { self::who(); } public static function test2() { static::who(); // 后期静态绑定 } public static function getInstance() { var_dump(new self); echo '--'; var_dump(new static); echo '<br>'; // 后期静态绑定 } } class B extends A { protected $name = 'B'; static $alias = 'b'; const HASH = 'sha1'; public static function who() { echo __CLASS__; echo ' [ This is B ]'; echo '<br>'; } } class C extends B { public static function who() { echo __CLASS__; echo ' [ This is C]'; echo '<br>'; } } (new A)->dd(); // A--a--md5--a--md5--object(A)#2 (1) { ["name":protected]=> string(1) "A" } --object(A)#1 (1) { ["name":protected]=> string(1) "A" } --object(A)#2 (1) { ["name":protected]=> string(1) "A" } (new B)->dd(); // B--b--sha1--a--md5--object(A)#2 (1) { ["name":protected]=> string(1) "A" } --object(B)#1 (1) { ["name":protected]=> string(1) "B" } --object(B)#2 (1) { ["name":protected]=> string(1) "B" } A::who(); // A [ This is A ] B::who(); // B [ This is B ] A::test(); // A [ This is A ] B::test(); // A [ This is A ] A::test2(); // A [ This is A ] B::test2(); // B [ This is B ] C::test2(); // C [ This is C] A::getInstance(); // object(A)#1 (1) { ["name":protected]=> string(1) "A" } --object(A)#1 (1) { ["name":protected]=> string(1) "A" } B::getInstance(); // object(A)#1 (1) { ["name":protected]=> string(1) "A" } --object(B)#1 (1) { ["name":protected]=> string(1) "B" }
总结说明:
self 和 __CLASS__,都是对当前类的静态引用,取决于定义当前方法所在的类。也就是说,self 写在哪个类里面, 它引用的就是谁。
$this 指向的是实际调用时的对象,也就是说,实际运行过程中,谁调用了类的属性或方法,$this 指向的就是哪个对象。但 $this 不能访问类的静态属性和常量,且 $this 不能存在于静态方法中。
static 关键字除了可以声明类的静态成员(属性和方法)外,还有一个非常重要的作用就是后期静态绑定。
self 可以用于访问类的静态属性、静态方法和常量,但 self 指向的是当前定义所在的类,这是 self 的限制。
$this 指向的对象所属的类和 static 指向的类相同。
static 可以用于静态或非静态方法中,也可以访问类的静态属性、静态方法、常量和非静态方法,但不能访问非静态属性。
静态调用时,static 指向的是实际调用时的类;非静态调用时,static 指向的是实际调用时的对象所属的类。
后期静态绑定
后期静态绑定(也叫延迟静态绑定),可用于在继承范围内引用静态调用的类,也就是代码运行时最初调用的类。
后期静态绑定本想通过引入一个新的关键字来表示,但最终还是沿用了 static 关键字。
工作原理
确切地说,static 后期静态绑定的工作原理是存储了上一个非转发调用(non-forwarding call)的类名。
当进行静态方法调用时,该类名(static指向的类名)为明确指定的那个(通常是 :: 运算符的左侧部分),即实际调用时的类。
如上述示例中的:
A::test2(); B::test2();
static 和 self 的区别:
self 可以用于访问类的静态属性、静态方法和常量,但 self 指向的是当前定义所在的类,这是 self 的限制。
static 也可以用于访问类的静态属性、静态方法和常量,static 指向的是实际调用时的类。
当进行非静态方法调用时,该类名(static指向的类名)为该对象所属的类,即实际调用时的对象所属的类。
如上述示例中的:
(new A)->dd();
(new B)->dd();
static 和 $this 有点类似,但又有区别:
$this 指向的对象所属的类和 static 指向的类相同。
$this 不能用于静态方法中,也不能访问类的静态属性和常量。
$this 指向的是实际调用的对象。
static 可以用于静态或非静态方法中,也可以访问类的静态属性、静态方法、常量和非静态方法,但不能访问非静态属性。
static 指向的是实际调用时的对象所属的类。
转发调用(forwarding call)
所谓的转发调用(forwarding call)指的是通过以下几种方式进行的静态调用:self::,parent::,static:: 以及 forward_static_call() 。
可用 get_called_class() 函数来获取被调用的方法所在的类名。
以下四种形式的调用,都是转发调用:
self::
parent::
static::
forward_static_call()
除此之外的调用,就是非转发调用。
非转发调用(non-forwarding call)
后期静态绑定的工作原理是存储了上一个非转发调用(non-forwarding call)的类名。
通过具体的类名或具体的对象进行的调用都是非转发调用。
A::test2(); B::test2(); (new A)->dd(); (new B)->dd();
注意事项
非静态环境下的私有方法的查找顺序
在非静态环境下,在类的非静态方法中,使用 $this 和 static 调用类的私有方法时,执行方式有所不同。
$this 会优先寻找所在定义范围(父类)中的私有方法,如果存在就调用。
static 是先到它指向的类(子类)中寻找私有方法,如果找到了就会报错,因为私有方法只能在它所定义的类内部调用;如果没找到,再去所在定义范围(父类)中寻找该私有方法,如果存在就调用。
具体来说,$this 会先到所在定义范围内寻找私有方法,再到它指向的对象所属的类中寻找私有方法,然后寻找公有方法,最后到所在定义范围内寻找公共方法。只要找到了匹配的方法,就调用,并停止查找。
而 static 则是先到它指向的类中寻找私有方法,再寻找共有方法;然后到所在定义范围内寻找私有方法,再寻找共有方法。只要找到了匹配的方法,就调用,并停止查找。
以上内容来源于百科书,可以关注我了解更多.
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/288229.html