First, we introduce the concept of late static binding through a piece of code:
class A { public static function who() { echo __CLASS__, PHP_EOL; } public static function test() { self::who(); } } class B extends A { public static function who() { echo __CLASS__, PHP_EOL; } } B::test(); // A
In this code, we use the self keyword. When using class B to call the test() static method, self points to the who() method of class A, so the output is A. Don't get excited, this is ordinary static binding. What the self keyword calls depends on the class in which it is defined. That is to say, no matter how it is inherited and which subclass is used to call the test() method, the self keyword will call the who() method of class A.
What about late static binding? In fact, it is a bit like an instantiated class object. Each instantiated object calls itself, not the attribute method of the parent class. Ordinary static calls are not like this, but in reality we have such a need to call static property methods in the same way as instantiated objects. At this time, we can use the static keyword to implement late static binding.
class C { public static function who() { echo __CLASS__, PHP_EOL; } public static function test() { static::who(); } } class D extends C { public static function who() { echo __CLASS__, PHP_EOL; } } D::test(); // D
When the static keyword is used, the who() called inside the test() method called by class D here is class D itself.
The definition in the official documentation is as follows:
When making a static method call, the class name is the one explicitly specified (usually on the left side of the :: operator); When a non-static method call is made, it is the class to which the object belongs.
This feature is named "late static binding" from a language internal perspective. "Late binding" means that static:: is no longer resolved to the class in which the current method is defined, but is calculated at actual runtime. It can also be called "static binding" because it can be used for (but is not limited to) calls to static methods.
In addition to the self and static keywords, we also have a parent keyword. The meaning of this keyword is obvious, calling the static content of the parent class. We use three keywords at the same time to test:
class E { public static function who() { echo __CLASS__, PHP_EOL; } public static function test() { self::who(); static::who(); } } class F extends E { public static function who() { echo __CLASS__, PHP_EOL; } } class G extends F { public static function who() { parent::who(); echo __CLASS__, PHP_EOL; } } G::test(); // E // F // G
Finally, let’s look at two PHP methods. One is the get_called_class() method, which is used to get which class is currently called. In the static method, you can determine which class the current class is based on the calling method to perform other business logic operations. The other is the forward_static_call() method, which is used for calling static methods.
class H { public static function who() { echo __CLASS__ . ':' . join(',', func_get_args()), PHP_EOL; } public static function test() { echo get_called_class(), PHP_EOL; forward_static_call('who', 'a', 'b'); // xxx:a,b forward_static_call(['I', 'who'], 'c', 'd'); // I:c,d forward_static_call_array(['H', 'who'], ['e', 'f']); // H:e,f } } class I extends H { public static function who() { echo __CLASS__ . ':' . join(',', func_get_args()), PHP_EOL; } } function who() { echo 'xxx:' . join(',', func_get_args()), PHP_EOL; } H::test(); // H // xxx:a,b // I:c,d // H:e,f I::test(); // I // xxx:a,b // I:c,d // H:e,f
Note that if forward_static_call() does not specify a class name, the global method will be called. forward_static_call_array() passes parameters using an array.
测试代码: https://github.com/zhangyue0503/dev-blog/blob/master/php/202001/source/%E5%90%8E%E6%9C%9F%E9%9D%99%E6%80%81%E7%BB%91%E5%AE%9A%E5%9C%A8PHP%E4%B8%AD%E7%9A%84%E4%BD%BF%E7%94%A8.php