늦은 정적 바인딩

PHP는 정적 상속 컨텍스트에서 호출된 클래스를 참조하는 데 사용할 수 있는 늦은 정적 바인딩이라는 기능을 구현합니다.

보다 정확하게는 늦은 정적 바인딩은 마지막 "비전달 호출"에서 명명된 클래스를 저장하여 작동합니다. 정적 메서드 호출의 경우 이것은 명시적으로 명명된 클래스입니다(일반적으로 :: 연산자 왼쪽에 있는 클래스). 비 정적 메서드 호출의 경우 개체의 클래스입니다. "전달 호출"은 self::, parent::, static:: 또는 클래스 계층 구조에서 위로 올라갈 경우 forward_static_call()에 의해 도입되는 정적 호출입니다. get_called_class() 함수는 호출된 클래스의 이름을 가진 문자열을 검색하는 데 사용할 수 있으며 static::은 해당 범위를 소개합니다.

이 기능은 내부 관점을 염두에 두고 "늦은 정적 바인딩"으로 명명되었습니다. "늦은 바인딩"은 static::이 메서드가 정의된 클래스를 사용하여 해결되지 않고 런타임 정보를 사용하여 계산된다는 사실에서 비롯됩니다. 정적 메서드 호출에 사용할 수 있으므로 "정적 바인딩"이라고도 합니다.


self:: 제약사항

self:: 또는 __CLASS__와 같은 현재 클래스에 대한 정적 참조는 정의된 위치에서와 같이 함수가 속한 클래스를 사용하여 해결됩니다.

예제 #1 self:: 사용법

                  
<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        self::who();
    }
}

class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}

B::test();
?>
                  
                

위의 예는 다음을 출력합니다.

A
                

늦은 정적 바인딩의 사용법

늦은 정적 바인딩은 런타임에 처음에 호출된 클래스를 참조하는 키워드를 도입하여 이러한 제한을 해결하려고 합니다. 기본적으로 이전 예제에서 test()에서 B를 참조할 수 있는 키워드입니다. 새로운 키워드를 도입하지 않고 이미 예약된 static을 사용하기로 결정했습니다.

예제 #2 static:: 간단한 사용법

                  
<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        static::who(); // Here comes Late Static Bindings
    }
}

class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}

B::test();
?>
                  
                

위의 예는 다음을 출력합니다.

B
                

메모: 비정적 컨텍스트에서 호출된 클래스는 개체 인스턴스의 클래스가 됩니다. $this->는 같은 범위에서 private 메소드를 호출하려고 하므로 static::을 사용하면 다른 결과가 나올 수 있습니다. 또 다른 차이점은 static::은 정적 속성만 참조할 수 있다는 것입니다.

예제 #3 static:: 비정적 컨텍스트에서의 사용법

                  
<?php
class A {
    private function foo() {
        echo "success!\n";
    }
    public function test() {
        $this->foo();
        static::foo();
    }
}

class B extends A {
   /* foo() will be copied to B, hence its scope will still be A and
    * the call be successful */
}

class C extends A {
    private function foo() {
        /* original method is replaced; the scope of the new one is C */
    }
}

$b = new B();
$b->test();
$c = new C();
$c->test();   //fails
?>
                  
                

위의 예는 다음을 출력합니다.

success!
success!
success!


Fatal error:  Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
                

메모: 늦은 정적 바인딩의 해결은 폴백 없이 완전히 해결된 정적 호출에서 중지됩니다. 반면에 parent:: 또는 self::와 같은 키워드를 사용하는 정적 호출은 호출 정보를 전달합니다.

예제 #4 전달(Forwarding)과 비전달(non-forwarding) 호출

                    
  <?php
class 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();
    }

    public static function who() {
        echo __CLASS__."\n";
    }
}
class C extends B {
    public static function who() {
        echo __CLASS__."\n";
    }
}

C::test();
?>
                    
                  

위의 예는 다음을 출력합니다.

A
C
C