답변:
PHP 매뉴얼에서 Late Static Bindings 를 반드시 읽으십시오 . 그러나 간단한 요약을 해 드리겠습니다.
기본적으로 self
키워드가 동일한 상속 규칙을 따르지 않는다는 사실로 요약됩니다 . self
항상 사용되는 클래스로 확인됩니다. 즉, 부모 클래스에서 메서드를 만들어 자식 클래스에서 호출하면 self
예상대로 자식을 참조하지 않습니다.
늦은 정적 바인딩은 static
키워드 의 새로운 용도를 소개 하며이 단점을 해결합니다. 를 사용할 때 static
처음 사용하는 클래스를 나타냅니다. 런타임 클래스에 '바인딩'됩니다.
이것이 두 가지 기본 개념입니다. 방법은 self
, parent
과 static
가 작동 static
더 세부 사항에 미묘한, 그래서보다는 이동 될 수 놀이에, 나는 강하게 당신이 매뉴얼 페이지 예제를 공부하는 것이 좋습니다 것입니다. 각 키워드의 기본 사항을 이해하면 어떤 결과를 얻을 수 있는지보기 위해 예제가 필요합니다.
self
키워드는 상속 규칙을 따르지 않습니다. self
항상 키워드 가 사용되는 클래스로 해석됩니다." - self
비 정적 메서드처럼을 통해 자식 개체에서 부모의 정적 메서드를 호출 할 수 없다는 의미는 아닙니다 . 당신은 옳은 것을 의미 할 수도 있지만 다시 말해야합니다. 자녀가 똑같은 이름을 가진 회원을 가진 후에는 모든 것이 중요합니다. 왜냐하면 당신은 static::
대신에 어떤 회원을 참조 할 것인지 결정할 수 있기 때문 입니다.
에서 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::
해당 범위를 소개 하는 데 사용할 수 있습니다 .
명백한 행동은 없습니다 :
다음 코드는 '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'가 표시됩니다.
"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
차이점을 보여주는 가장 간단한 예입니다.
참고, 자기 : $ 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
또한 자식 클래스에서 정적 변수를 업데이트하는지 확인하십시오. 자식 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;
}
}