PHP에서 늦은 정적 바인딩은 정확히 무엇입니까?


답변:


198

PHP 매뉴얼에서 Late Static Bindings 를 반드시 읽으십시오 . 그러나 간단한 요약을 해 드리겠습니다.

기본적으로 self키워드가 동일한 상속 규칙을 따르지 않는다는 사실로 요약됩니다 . self항상 사용되는 클래스로 확인됩니다. 즉, 부모 클래스에서 메서드를 만들어 자식 클래스에서 호출하면 self예상대로 자식을 참조하지 않습니다.

늦은 정적 바인딩은 static키워드 의 새로운 용도를 소개 하며이 단점을 해결합니다. 를 사용할 때 static처음 사용하는 클래스를 나타냅니다. 런타임 클래스에 '바인딩'됩니다.

이것이 두 가지 기본 개념입니다. 방법은 self, parentstatic가 작동 static더 세부 사항에 미묘한, 그래서보다는 이동 될 수 놀이에, 나는 강하게 당신이 매뉴얼 페이지 예제를 공부하는 것이 좋습니다 것입니다. 각 키워드의 기본 사항을 이해하면 어떤 결과를 얻을 수 있는지보기 위해 예제가 필요합니다.


나는 [링크] (아웃을 확인,이 문서가 정말 유용하고 설명 발견 techflirt.com/tutorials/oop-in-php/late-static-binding.html )
사데 Shaikhi

"... self키워드는 상속 규칙을 따르지 않습니다. self항상 키워드 가 사용되는 클래스로 해석됩니다." - self비 정적 메서드처럼을 통해 자식 개체에서 부모의 정적 메서드를 호출 할 수 없다는 의미는 아닙니다 . 당신은 옳은 것을 의미 할 수도 있지만 다시 말해야합니다. 자녀가 똑같은 이름을 가진 회원을 가진 후에는 모든 것이 중요합니다. 왜냐하면 당신은 static::대신에 어떤 회원을 참조 할 것인지 결정할 수 있기 때문 입니다.
DanMan

81

에서 PHP : 늦은 정적 바인딩 - 수동 :

PHP 5.3.0부터 PHP는 정적 상속이라는 맥락에서 호출 된 클래스를 참조하는 데 사용할 수있는 후기 정적 바인딩이라는 기능을 구현합니다.

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

예를 보자.

<?php
    class Car
    {
        public static function run()
        {
            return static::getName();
        }

        private static function getName()
        {
            return 'Car';
        }
    }

    class Toyota extends Car
    {
        public static function getName()
        {
            return 'Toyota';
        }
    }

    echo Car::run(); // Output: Car
    echo Toyota::run(); // Output: Toyota
?>

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


1
이 게시물은 인용 마커가없는 php.net 기사 의 약 80 % 정도 입니다.
WoodrowShigeru

22

명백한 행동은 없습니다 :

다음 코드는 'alphabeta'를 생성합니다.

class alpha {

    function classname(){
        return __CLASS__;
    }

    function selfname(){
        return self::classname();
    }

    function staticname(){
        return static::classname();
    }
}

class beta extends alpha {

    function classname(){
        return __CLASS__;
    }
}

$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta

그러나 베타 클래스에서 classname 함수 선언을 제거하면 결과로 'alphaalpha'가 표시됩니다.


1
아주 좋아요 PHP 매뉴얼에도 같은 내용이 나와 있지만 훨씬 명확합니다. 참조 : php.net/manual/en/language.oop5.late-static-bindings.php (예 4 참조)
musicin3d

11

"PHP Master write 첨단 코드"라는 책에서 인용하고 있습니다.

늦은 정적 바인딩은 PHP 5.3에서 소개 된 기능입니다. 이를 통해 부모 클래스에서 정적 메서드를 상속하고 호출되는 자식 클래스를 참조 할 수 있습니다.

이것은 정적 메소드를 가진 추상 클래스를 가질 수 있고 self :: method () 대신 static :: method () 표기법 을 사용하여 하위 클래스의 구체적인 구현을 참조 할 수 있음을 의미합니다 .

공식 PHP 문서도 참조하십시오 : http://php.net/manual/en/language.oop5.late-static-bindings.php


늦은 정적 바인딩을 설명하는 가장 명확한 방법은 간단한 예입니다. 아래의 두 클래스 정의를 살펴보고 계속 읽으십시오.

class Vehicle {
    public static function invokeDriveByStatic() {
        return static::drive(); // Late Static Binding
    }
    public static function invokeStopBySelf() {
        return self::stop(); // NOT Late Static Binding
    }
    private static function drive(){
        return "I'm driving a VEHICLE";
    }
    private static function stop(){
        return "I'm stopping a VEHICLE";
    }
}

class Car extends Vehicle  {
    protected static function drive(){
        return "I'm driving a CAR";
    }
    private static function stop(){
        return "I'm stopping a CAR";
    }
}

우리는 부모 클래스 (차량)와 자식 클래스 (차)를 봅니다. 학부모 클래스에는 두 가지 공개 메소드가 있습니다.

  • invokeDriveByStatic
  • invokeStopBySelf

부모 클래스에는 2 개의 개인 메소드가 있습니다 :

  • drive
  • stop

자식 클래스는 다음 두 가지 메소드를 대체합니다.

  • drive
  • stop

이제 public 메소드를 호출 해 봅시다 :

  • invokeDriveByStatic
  • invokeStopBySelf

자신에게 물어 : 어떤 클래스를 발동를 invokeDriveByStatic/ invokeStopBySelf? 부모 또는 자식 수업?

아래를 살펴보십시오.

// This is NOT Late Static Binding
// Parent class invokes from Parent. In this case Vehicle.
echo Vehicle::invokeDriveByStatic(); // I'm driving a VEHICLE
echo Vehicle::invokeStopBySelf(); // I'm stopping a VEHICLE

// !!! This is Late Static Binding !!!!
// Child class invokes an inherited method from Parent.
// Child class = Car, Inherited method = invokeDriveByStatic().
// The inherited method invokes a method that is overridden by the Child class.
// Overridden method = drive()
echo Car::invokeDriveByStatic(); // I'm driving a CAR

// This is NOT Late Static Binding
// Child class invokes an inherited method from Parent.
// The inherited method invokes a method inside the Vehicle context.
echo Car::invokeStopBySelf(); // I'm stopping a VEHICLE

static키워드는 단일 디자인 패턴으로 사용됩니다. 링크 참조 : https://refactoring.guru/design-patterns/singleton/php/example


7

차이점을 보여주는 가장 간단한 예입니다.
참고, 자기 : $ C를

class A
{
    static $c = 7;

    public static function getVal()
    {
        return self::$c;
    }
}

class B extends A
{
    static $c = 8;
}

B::getVal(); // 7

늦은 정적 바인딩, 정적 :: $ c 참고

class A
{
    static $c = 7;

    public static function getVal()
    {
        return static::$c;
    }
}

class B extends A
{
    static $c = 8;
}

B::getVal(); // 8

4

예를 들면 다음과 같습니다.

abstract class Builder {
    public static function build() {
        return new static;
    }
}

class Member extends Builder {
    public function who_am_i() {
         echo 'Member';
    }
}

Member::build()->who_am_i();

4

"왜 이것을 사용해야합니까?" 관점에서 볼 때, 기본적으로 정적 메소드가 해석 / 실행되는 컨텍스트를 변경하는 방법입니다.

self컨텍스트는 메소드를 원래 정의한 컨텍스트입니다. 를 사용하면 static전화를 거는 사람입니다.


1

또한 자식 클래스에서 정적 변수를 업데이트하는지 확인하십시오. 자식 B가 자식 C를 업데이트하면 예기치 않은 결과가 발견되었습니다.

class A{
    protected static $things;
}

class B extends A {
    public static function things(){
        static::$things[1] = 'Thing B';
        return static::$things; 
    }
}

class C extends A{
    public static function things(){
        static::$things[2] = 'Thing C';
        return static::$things;        
    }
}

print_r(C::things());
// Array (
//   [2] => Thing C
// )

B::things();

print_r(C::things()); 
// Array (
//    [2] => Thing C
//    [1] => Thing B
// )

각 하위 클래스에서 동일한 변수를 선언하여이를 수정할 수 있습니다. 예를 들면 다음과 같습니다.

class C extends A{
    protected static $things; // add this and B will not interfere!

    public static function things(){
        static::$things[2] = 'Thing C';
        return static::$things;        
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.