Detailed explanation of the differences between self, static, $this and late static binding in PHP

不言
Release: 2023-03-23 17:18:01
Original
2857 people have browsed it

The content shared with you in this article is about the differences between self, static, and $this in PHP and the detailed explanation of late static binding. It has certain reference value. Friends in need can refer to it


The difference between self, static and $this


In order to better understand the difference between self, static and $this, let’s first look at an example .

<?phpclass A {    protected $name = &#39;A&#39;;    static $alias = &#39;a&#39;;    const HASH = &#39;md5&#39;;    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" }
Copy after login

Summary description:

  • self and __CLASS__ are static references to the current class, depending on the class in which the current method is defined. . In other words, which class self is written in will be the one it refers to.

  • $this points to the object when it is actually called. That is to say, whoever calls the properties or methods of the class during the actual running process, $this points to the object. But $this cannot access static properties and constants of the class, and $this cannot exist in static methods.

  • # In addition to declaring static members (properties and methods) of a class, the static keyword also plays a very important role in late static binding.

  • self can be used to access static properties, static methods and constants of a class, but self points to the class where the current definition is located. This is a limitation of self.

  • $this points to an object that belongs to the same class as static points to.

  • static can be used in static or non-static methods, and can also access static properties, static methods, constants and non-static methods of the class, but cannot access non-static properties.

  • When calling statically, static points to the class that is actually called; when calling non-statically, static points to the class to which the object is actually called.

Late static binding

Late static binding (also called delayed static binding) can be used to reference statically called classes in the inheritance scope, that is, code The class that is initially called at runtime.

Later static binding was originally intended to be expressed by introducing a new keyword, but in the end the static keyword was used.

工作原理

确切地说,static 后期静态绑定的工作原理是存储了上一个非转发调用(non-forwarding call)的类名。

当进行静态方法调用时,该类名(static指向的类名)为明确指定的那个(通常是 :: 运算符的左侧部分),即实际调用时的类。

如上述示例中的:

A::test2(); B::test2();
Copy after login

static 和 self 的区别:

  • self 可以用于访问类的静态属性、静态方法和常量,但 self 指向的是当前定义所在的类,这是 self 的限制。

  • static 也可以用于访问类的静态属性、静态方法和常量,static 指向的是实际调用时的类。

当进行非静态方法调用时,该类名(static指向的类名)为该对象所属的类,即实际调用时的对象所属的类。

如上述示例中的:

(new A)->dd(); 
(new B)->dd();
Copy after login

static 和 $this 有点类似,但又有区别:

  • $this 指向的对象所属的类和 static 指向的类相同。

  • $this 不能用于静态方法中,也不能访问类的静态属性和常量。

  • $this 指向的是实际调用的对象。

  • static 可以用于静态或非静态方法中,也可以访问类的静态属性、静态方法、常量和非静态方法,但不能访问非静态属性。

  • static 指向的是实际调用时的对象所属的类。

Forwarding call (forwarding call)

The so-called forwarding call (forwarding call) refers to static calls made in the following ways: self::, parent::, static:: and forward_static_call().

You can use the get_called_class() function to get the class name of the called method.

The following four forms of calls are all forwarding calls:

  • self::

  • parent::

  • static::

  • ##forward_static_call()

Calls other than this are non-forwarding transfer.

Non-forwarding call(non-forwarding call)

The working principle of late static binding is to store the previous non-forwarding call(non -forwarding call) class name.

Calls made through specific class names or specific objects are non-forwarded calls.

for example:

A::test2(); 
B::test2(); 

(new A)->dd(); 
(new B)->dd();
Copy after login

注意事项

非静态环境下的私有方法的查找顺序

在非静态环境下,在类的非静态方法中,使用 $this 和 static 调用类的私有方法时,执行方式有所不同。

  • $this 会优先寻找所在定义范围(父类)中的私有方法,如果存在就调用。

  • static 是先到它指向的类(子类)中寻找私有方法,如果找到了就会报错,因为私有方法只能在它所定义的类内部调用;如果没找到,再去所在定义范围(父类)中寻找该私有方法,如果存在就调用。

具体来说,$this 会先到所在定义范围内寻找私有方法,再到它指向的对象所属的类中寻找私有方法,然后寻找公有方法,最后到所在定义范围内寻找公共方法。只要找到了匹配的方法,就调用,并停止查找。

而 static 则是先到它指向的类中寻找私有方法,再寻找共有方法;然后到所在定义范围内寻找私有方法,再寻找共有方法。只要找到了匹配的方法,就调用,并停止查找。

下面是一个例子:

<?php
 class  A  {    private function  foo () {
        var_dump($this); echo '--';
        var_dump(new static); echo '--';        echo __CLASS__; echo '--';        echo get_called_class();        echo '<br>';
    }    public function  test () {        $this -> foo ();        static:: foo ();        echo '<br>';
    }
}class  B  extends  A  { }class  C  extends  A  {    private function foo () {        echo 'this is C';
    }
}

(new  B())->test();
(new  C())->test();
Copy after login

输出结果为:

object(B)#1 (0) { } --object(B)#2 (0) { } --A--B
object(B)#1 (0) { } --object(B)#2 (0) { } --A--B

object(C)#1 (0) { } --object(C)#2 (0) { } --A--C

Fatal error: Uncaught Error: Call to private method C::foo() from context 'A'
Copy after login

关于后期静态绑定的解析

后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止。如果静态调用使用了 parent:: 或者 self:: 等转发调用的形式,将会转发调用信息。

<?phpclass  A  {    public static function  foo () {        static:: who ();
    }    public static function  who () {        echo  __CLASS__ . "\n" ;
    }
}class  B  extends  A  {    public static function  test () {
        A :: foo ();        parent :: foo ();        self :: foo ();        static::foo();
        forward_static_call(['A', 'foo']);        echo '<br>';
    }    public static function  who () {        echo  __CLASS__ . "\n" ;
    }
}class  C  extends  B  {    public static function  who () {        echo  __CLASS__ . "\n" ;
    }    public static function test2() {        self::test();
    }
}class  D  extends  C  {    public static function  who () {        echo  __CLASS__ . "\n" ;
    }
}

B::foo();
B::test();

C::foo();
C::test();

D::foo();
D::test2();
Copy after login

以上的输出结果为:

B A B B B B 
C A C C C C D A D D D D
Copy after login

static 后期静态绑定的工作原理是存储了上一个非转发调用(non-forwarding call)的类名。请记住这句话。

下面的例子是非转发调用。

A::foo();  // 输出 AB::foo();   // 输出 BC::foo();   // 输出 C
Copy after login

后期静态绑定 static ,是定义在了 foo() 方法中,哪个类通过非转发调用的形式调用 foo() 方法, foo() 方法中的 static 指向的就是哪个类。

但是,如果通过转发调用的形式,调用 foo() 方法,如:

parent :: foo ();self :: foo ();static::foo();forward_static_call(['A', 'foo']);
Copy after login

那么,就以转发调用代码所在的方法 test() 为准,哪个类通过非转发调用的形式调用 test() 方法, foo() 方法中的 static 指向的就是哪个类。

假如调用 test() 方法时,也采用了转发调用的形式,如:

public static function test2() {    self::test();
}
Copy after login

那么,就以 test2() 方法为准 ... 依次类推。

也就是说,在使用了后期静态绑定的基类中,后期静态绑定所在的方法如果被转发调用,则 static 的指向,会一直向上追溯,直到遇到非转发调用的形式。

相关推荐:

php中const与static的区别与使用


The above is the detailed content of Detailed explanation of the differences between self, static, $this and late static binding in PHP. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template