길고 슬픈 이야기입니다.
PHP 5.2가이 경고를 처음 도입했을 때 늦은 정적 바인딩 은 아직 언어로 제공되지 않았습니다. 후기 정적 바인딩에 익숙하지 않은 경우 다음과 같은 코드가 예상대로 작동하지 않습니다.
<?php
abstract class ParentClass {
static function foo() {
echo "I'm gonna do bar()";
self::bar();
}
abstract static function bar();
}
class ChildClass extends ParentClass {
static function bar() {
echo "Hello, World!";
}
}
ChildClass::foo();
엄격 모드 경고를 제외하고 위의 코드는 작동하지 않습니다. self::bar()
에서 통화 foo()
명확가 지칭 bar()
방법 ParentClass
때에도 foo()
방법으로 불린다 ChildClass
. 엄격 모드를 끈 상태에서이 코드를 실행하려고하면 " PHP 치명적 오류 : 추상 메소드 ParentClass :: bar ()를 호출 할 수 없습니다. "가 표시됩니다.
이 점을 감안할 때 PHP 5.2의 추상 정적 메서드는 쓸모가 없었습니다. 전체를 점 하고 다른 자식 클래스에 다른 구현을 제공 - 추상적 인 방법을 사용하여 당신이 그것을 호출 될 것 무엇을 구현 모른 채 메서드를 호출하는 코드를 작성할 수 있다는 것입니다. 그러나 PHP 5.2는 호출되는 자식 클래스의 정적 메서드를 호출하는 부모 클래스의 메서드를 작성하는 명확한 방법을 제공하지 않기 때문에 이러한 추상 정적 메서드 사용은 불가능합니다. 따라서 abstract static
PHP 5.2에서 사용하는 것은 잘못된 코드입니다.self
키워드가 작동 . 이것에 대해 경고를 던지는 것은 전적으로 합리적이었습니다.
그러나 PHP 5.3은 static
키워드 를 통해 메서드가 호출 된 클래스를 참조 할 수있는 기능이 추가되었습니다 ( self
항상 메서드가 정의 된 클래스를 참조 하는 키워드 와 달리 ). 위의 예제에서로 변경 self::bar()
하면 static::bar()
PHP 5.3 이상에서 제대로 작동합니다. 당신은 더 약 읽을 수 self
대 static
에 새 정적 대 새로운 자기 .
static 키워드를 추가하면 abstract static
경고 던지는 가 사라졌습니다. 후기 정적 바인딩의 주요 목적은 부모 클래스에 정의 된 메서드가 자식 클래스에 정의 된 정적 메서드를 호출 할 수 있도록하는 것이 었습니다. 추상 정적 메서드를 허용하는 것은 늦은 정적 바인딩이 존재하는 경우 합리적이고 일관된 것처럼 보입니다.
당신은 여전히 경고를 유지하기 위해 소송을 제기 할 수 있습니다. 예를 들어, PHP를 사용하면 추상 클래스의 정적 메서드를 호출 할 수 있기 때문에 위의 예에서 (으로 대체 self
하여 수정 한 후에도 static
) 깨져서 실제로 원하지 않는 공용 메서드 ParentClass::foo()
를 노출 한다고 주장 할 수 있습니다. 폭로. 비 정적 클래스 사용-즉, 모든 메서드 인스턴스 메서드를 만들고 자식을 만드는ParentClass
모든 싱글 톤 또는 무언가로 이 문제를 해결할 수 있습니다. 왜냐하면 ParentClass
, 추상이 될 수없고 인스턴스 메서드가 인스턴스화 할 수 없기 때문입니다. 불리다. 이 주장은 약하다고 생각합니다.ParentClass::foo()
큰 문제가 아니며 정적 클래스 대신 싱글 톤을 사용하는 것은 종종 불필요하게 장황하고 추악합니다.) 그러나 합리적으로 동의하지 않을 수 있습니다. 다소 주관적인 호출입니다.
그래서이 주장을 바탕으로 PHP 개발자는 경고를 언어로 유지했습니다.
어, 정확히는 아닙니다 .
위에 링크 된 PHP 버그 보고서 53081은 static::foo()
구조 추가로 인해 추상 정적 메서드가 합리적이고 유용하게 되었기 때문에 경고를 삭제하도록 요청했습니다 . Rasmus Lerdorf (PHP 창시자)는 요청을 가짜로 표시하는 것으로 시작하여 경고를 정당화하기 위해 긴 잘못된 추론을 거칩니다. 그런 다음 마지막으로이 교환이 발생합니다.
조르지오
알지만:
abstract class cA
{
//static function A(){self::B();} error, undefined method
static function A(){static::B();} // good
abstract static function B();
}
class cB extends cA
{
static function B(){echo "ok";}
}
cB::A();
라스무스
맞습니다, 그것이 정확히 작동하는 방식입니다.
조르지오
그러나 그것은 허용되지 않습니다 :(
라스무스
허용되지 않는 것은 무엇입니까?
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();
이것은 잘 작동합니다. 분명히 self :: B ()를 호출 할 수 없지만 static :: B ()는 괜찮습니다.
그의 예제에있는 코드가 "잘 작동한다"는 Rasmus의 주장은 거짓입니다. 아시다시피 엄격 모드 경고가 발생합니다. Strict 모드가 켜지지 않은 상태에서 테스트하고 있었던 것 같습니다. 그럼에도 불구하고 혼란스러운 Rasmus는 요청을 "가짜"로 잘못 종료했습니다.
그것이 경고가 여전히 언어로 된 이유입니다. 이것은 완전히 만족스러운 설명이 아닐 수 있습니다. 경고의 합리적 정당성이 있기를 바라면서 여기에 왔을 것입니다. 불행히도 현실 세계에서 때때로 선택은 합리적인 의사 결정이 아닌 일상적인 실수와 잘못된 추론에서 비롯됩니다. 이것은 단순히 그 시간 중 하나입니다.
운 좋게도 추정 가능한 Nikita Popov는 PHP RFC : Reclassify E_STRICT notices의 일부로 PHP 7의 언어에서 경고를 제거했습니다 . 궁극적으로 온전한 상태가 유지되었으며 PHP 7이 출시되면 abstract static
이 어리석은 경고를받지 않고 모두 즐겁게 사용할 수 있습니다 .