>백엔드 개발 >PHP 튜토리얼 >PHP의 self, static, $this 및 late static 바인딩 간의 차이점에 대한 자세한 설명

PHP의 self, static, $this 및 late static 바인딩 간의 차이점에 대한 자세한 설명

不言
不言원래의
2018-04-13 11:41:002885검색

이 글에서 공유한 내용은 PHP에서 self, static, $this의 차이점과 late static 바인딩에 대한 자세한 설명입니다. 필요한 친구들이 참고할 수 있습니다


self. , static 및 $this


self, static 및 $this의 차이점을 더 잘 이해하기 위해 먼저 예를 살펴보겠습니다.

<?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" }

요약:

  • self 및 __CLASS__는 현재 메서드가 정의된 클래스에 따라 현재 클래스에 대한 정적 참조입니다. 즉, 어느 클래스 self에 쓰여졌는지가 그것이 참조하는 클래스가 됩니다.

  • $this는 실제로 호출될 때 객체를 가리킵니다. 즉, 실제 실행 프로세스 중에 클래스의 속성이나 메서드를 호출하는 사람은 누구나 해당 객체를 가리킵니다. 그러나 $this는 클래스의 정적 속성과 상수에 액세스할 수 없으며 $this는 정적 메서드에 존재할 수 없습니다.

  • 클래스의 정적 멤버(속성 및 메서드)를 선언하는 것 외에도 static 키워드도 후기 정적 바인딩에서 매우 중요한 역할을 합니다.

  • self는 클래스의 정적 속성, 정적 메서드 및 상수에 액세스하는 데 사용할 수 있지만 self는 현재 정의가 있는 클래스를 가리킵니다. 이는 self의 한계입니다.

  • $this가 가리키는 객체는 static이 가리키는 클래스와 동일한 클래스에 속합니다.

  • static은 정적 또는 비정적 메서드에서 사용할 수 있으며 클래스의 정적 속성, 정적 메서드, 상수 및 비정적 메서드에도 액세스할 수 있지만 비정적 속성에는 액세스할 수 없습니다.

  • 정적으로 호출하는 경우 static은 실제로 호출되는 클래스를 가리키고, 비정적으로 호출하는 경우 static은 개체가 실제로 호출되는 클래스를 가리킵니다.

후기 정적 바인딩

후기 정적 바인딩(지연된 정적 바인딩이라고도 함)을 사용하면 코드가 실행될 때 처음에 호출되는 클래스인 상속 범위에서 정적으로 호출되는 클래스를 참조할 수 있습니다.

Late Static Binding은 원래 새로운 키워드를 도입하여 표현하려고 했으나 결국 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 指向的是实际调用时的对象所属的类。

전달 호출

소위 전달 호출은 self::, parent::, static:: 및 전달_정적_call() 방식으로 이루어진 정적 호출을 의미합니다.

get_called_class() 함수를 사용하여 호출된 메서드의 클래스 이름을 가져올 수 있습니다.

다음 네 가지 형태의 통화는 모두 앞으로의 통화입니다. 전달되지 않은 전화.

    비전달 호출
  • 후기 정적 바인딩
  • 은 이전
  • 비전달 호출

    (비전달 호출)의 클래스 이름을 저장하여 작동합니다.

  • 특정 클래스 이름이나 특정 객체를 통해 걸려온 전화는 착신전환되지 않는 전화입니다.
  • 예:

    A::test2(); 
    B::test2(); 
    
    (new A)->dd(); 
    (new B)->dd();

    注意事项

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

    在非静态环境下,在类的非静态方法中,使用 $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();

    输出结果为:

    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'

    关于后期静态绑定的解析

    后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止。如果静态调用使用了 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();

    以上的输出结果为:

    B A B B B B 
    C A C C C C D A D D D D

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

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

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

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

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

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

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

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

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

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

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

    相关推荐:

    php中const与static的区别与使用


위 내용은 PHP의 self, static, $this 및 late static 바인딩 간의 차이점에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.