This article summarizes the relevant knowledge points of PHP late static binding analysis and application. Friends who are interested in this can learn it.
Basic knowledge
1. Range parsing operator (::)
can be used to access static members, class constants, and can also be used to override properties and methods in the class.
The three special keywords self, parent and static are used to access its properties or methods inside the class definition.
parent is used to call overridden properties or methods in the parent class (where it appears, it will be resolved to the parent class of the corresponding class).
self is used to call methods or properties in this class (wherever it appears, it will be parsed into the corresponding class; note the difference with $this, $this points to the currently instantiated object ).
When a subclass overrides a method in its parent class, PHP will not call the overridden method in the parent class. Whether the method of the parent class is called depends on the child class.
2. The PHP kernel places the inheritance implementation of classes in the "compilation phase"
<?php class A{ const H = 'A'; const J = 'A'; static function testSelf(){ echo self::H; //在编译阶段就确定了 self解析为 A } } class B extends A{ const H = "B"; const J = 'B'; static function testParent(){ echo parent::J; //在编译阶段就确定了 parent解析为A } /* 若重写testSelf则能输出“B”, 且C::testSelf()也是输出“B” static function testSelf(){ echo self::H; } */ } class C extends B{ const H = "C"; const J = 'C'; } B::testParent(); B::testSelf(); echo "\n"; C::testParent(); C::testSelf();
Running result:
AA
AA
3.Static (static) keyword
- Used to declare static members when modifying class member functions and member variables.
- (After PHP5.3) A special class that represents static delayed binding before the scope resolver (::).
<?php function test() { static $count = 0; $count++; echo $count; if ($count < 10) { test(); } $count--; }
<?php class Foo { public static function aStaticMethod() { // ... } } Foo::aStaticMethod(); $classname = 'Foo'; $classname::aStaticMethod(); // 自PHP 5.3.0后,可以通过变量引用类 ?>
<?php class Foo { public static $my_static = 'foo'; public function staticValue() { return self::$my_static; //self 即 FOO类 } } class Bar extends Foo { public function fooStatic() { return parent::$my_static; //parent 即 FOO类 } } print Foo::$my_static . "\n"; $foo = new Foo(); print $foo->staticValue() . "\n"; print $foo->my_static . "\n"; // Undefined "Property" my_static print $foo::$my_static . "\n"; $classname = 'Foo'; print $classname::$my_static . "\n"; // As of PHP 5.3.0 print Bar::$my_static . "\n"; $bar = new Bar(); print $bar->fooStatic() . "\n"; ?>
Detailed analysis below
Late static binding1. Forwarded calls and non-forwarded calls
2. Working principle of late static binding
<?php class A { public static function foo() { echo __CLASS__."\n"; static::who(); } public static function who() { echo __CLASS__."\n"; } } class B extends A { public static function test() { echo "A::foo()\n"; A::foo(); echo "parent::foo()\n"; parent::foo(); echo "self::foo()\n"; self::foo(); } public static function who() { echo __CLASS__."\n"; } } class C extends B { public static function who() { echo __CLASS__."\n"; } } C::test(); /* * C::test(); //非转发调用 ,进入test()调用后,“上一次非转发调用”存储的类名为C * * //当前的“上一次非转发调用”存储的类名为C * public static function test() { * A::foo(); //非转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为A,然后实际执行代码A::foo(), 转 0-0 * parent::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处的parent解析为A ,转1-0 * self::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处self解析为B, 转2-0 * } * * * 0-0 * //当前的“上一次非转发调用”存储的类名为A * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为A, 故实际执行代码A::who(),即static代表A,进入who()调用后,“上一次非转发调用”存储的类名依然为A,因此打印 “A” * } * * 1-0 * //当前的“上一次非转发调用”存储的类名为C * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C” * } * * 2-0 * //当前的“上一次非转发调用”存储的类名为C * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C” * } */ 故最终结果为: A::foo() A A parent::foo() A C self::foo() A C
3. More examples of static late static binding
<?php class Mango { function classname(){ return __CLASS__; } function selfname(){ return self::classname(); } function staticname(){ return static::classname(); } } class Orange extends Mango { function parentname(){ return parent::classname(); } function classname(){ return __CLASS__; } } class Apple extends Orange { function parentname(){ return parent::classname(); } function classname(){ return __CLASS__; } } $apple = new Apple(); echo $apple->selfname() . "\n"; echo $apple->parentname() . "\n"; echo $apple->staticname(); ?> 运行结果: Mango Orange Apple
<?php class Mango { const NAME = 'Mango is'; public static function fruit() { $args = func_get_args(); echo static::NAME, " " . join(' ', $args) . "\n"; } } class Orange extends Mango { const NAME = 'Orange is'; public static function fruit() { echo self::NAME, "\n"; forward_static_call(array('Mango', 'fruit'), 'my', 'favorite', 'fruit'); forward_static_call('fruit', 'my', 'father\'s', 'favorite', 'fruit'); } } Orange::fruit('NO'); function fruit() { $args = func_get_args(); echo "Apple is " . join(' ', $args). "\n"; } ?> 运行结果: Orange is Orange is my favorite fruit Apple is my father's favorite fruit
<?php class Mango { static public function fruit() { echo get_called_class() . "\n"; } } class Orange extends Mango { // } Mango::fruit(); Orange::fruit(); ?> 运行结果: Mango Orange
Application
So, you can use late static binding to solve the singleton inheritance problem.
<?php // new self 得到的单例都为A。 class A { protected static $_instance = null; protected function __construct() { //disallow new instance } protected function __clone(){ //disallow clone } static public function getInstance() { if (self::$_instance === null) { self::$_instance = new self(); } return self::$_instance; } } class B extends A { protected static $_instance = null; } class C extends A{ protected static $_instance = null; } $a = A::getInstance(); $b = B::getInstance(); $c = C::getInstance(); var_dump($a); var_dump($b); var_dump($c); 运行结果: E:\code\php_test\apply\self.php:37: class A#1 (0) { } E:\code\php_test\apply\self.php:38: class A#1 (0) { } E:\code\php_test\apply\self.php:39: class A#1 (0) { }
<?php // new static 得到的单例分别为D,E和F。 class D { protected static $_instance = null; protected function __construct(){} protected function __clone() { //disallow clone } static public function getInstance() { if (static::$_instance === null) { static::$_instance = new static(); } return static::$_instance; } } class E extends D { protected static $_instance = null; } class F extends D{ protected static $_instance = null; } $d = D::getInstance(); $e = E::getInstance(); $f = F::getInstance(); var_dump($d); var_dump($e); var_dump($f); 运行结果: E:\code\php_test\apply\static.php:35: class D#1 (0) { } E:\code\php_test\apply\static.php:36: class E#2 (0) { } E:\code\php_test\apply\static.php:37: class F#3 (0) { }
AjaxSubmit() submits the file file
Two methods for Ajax to solve redundant refreshes
A brief analysis and solutions to Ajax synchronization and asynchronous issues
The above is the detailed content of Detailed explanation of PHP late static binding analysis and application. For more information, please follow other related articles on the PHP Chinese website!