Detailed description of PHP static binding Analysis and Application in later stages, detailed description of php static binding
Basic knowledge
1. Range Resolution operator (::)
- It can be used to access static members, class constants, and overwrite attributes and methods in the class.
- The three special keywords self, parent, and static are used to access their attributes or methods within the class definition.
- Parent is used to call the override attributes or methods in the parent class (where it appears, it will be resolved as the parent class of the corresponding class ).
- Self is used to call methods or attributes in this class (where it appears, it will be resolved to the corresponding class; note the difference with $ this, $ this points to the currently instantiated object ).
- When a subclass overwrites the methods in its parent class, PHP does not call the methods already overwritten in the parent class. Whether to call the method of the parent class depends on the subclass.
2. the PHP kernel puts the class inheritance implementation in the "compilation stage"
<? Phpclass A {const H = 'a'; const J = 'a'; static function testSelf () {echo self: H; // At the compilation stage, self is resolved to A} class B extends A {const H = "B"; const J = 'B'; static function testParent () {echo parent: J; // At the compilation stage, parent is resolved to A}/* If testSelf is rewritten, "B" can be output, and C: testSelf () it also outputs "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
Conclusion:
Self: and parent: appear in the definition of a Class X, it will be parsed as the corresponding class X, unless the method of the parent class is overwritten in the subclass.
3. Static (Static) KEYWORDS
Purpose:
-The static keyword for modifying variables in the function body is used to define static local variables.
-Used to declare static members when modifying class member functions and member variables.
-(After PHP5.3) a special class with static latency bound before the scope Parser.
Example:
Define static local variables (location: in the local function)
Feature: static variables only exist in the local function domain, but their values are not lost when the program runs out of this scope.
<?phpfunction test(){ static $count = 0; $count++; echo $count; if ($count < 10) { test(); } $count--;}
Define static methods and static attributes
A) declared class attributes or methods are static, and you can directly access them without instantiating classes.
B) Static attributes cannot be accessed through an object that has been instantiated in the class (but static attributes can be accessed)
C) if no access control is specified, attributes and methods are considered public.
D) Because static methods can be called without passing through objects, the pseudo variable $ this is not available in static methods.
E) Static attributes cannot be accessed by objects through the-> operator.
F) calling a non-static method in static mode will result in an E_STRICT error.
G) Just like all other PHP static variables, static attributes can only be initialized as text or constants and cannot use expressions. Therefore, static attributes can be initialized as integers or arrays, but they cannot be initialized as another variable or function return value or point to an object.
A. Static Method example (location: class method definition)
<? Phpclass Foo {public static function aStaticMethod (){//...}} foo: aStaticMethod (); $ classname = 'foo'; $ classname: aStaticMethod (); // After PHP 5.3.0, can classes be referenced through variables?>
B. Static Property example (location: Class Attribute definition)
<? Phpclass Foo {public static $ my_static = 'foo'; public function staticValue () {return self: $ my_static; // self is the FOO class} class Bar extends Foo {public function fooStatic () {return parent: $ my_static; // parent is the FOO class} 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"; $ classnail m E = 'foo'; print $ classname: $ my_static. "\ n"; // As of PHP 5.3.0print Bar: $ my_static. "\ n"; $ bar = new Bar (); print $ bar-> fooStatic (). "\ n";?>
C. Used for static binding in the later stage (in the class method, used to modify variables or methods)
The following detailed analysis
Late static binding)
Since PHP 5.3.0, PHP has added a function called static binding later, which is used to reference static calling classes within the inheritance scope.
1. Forward call and non-forward call
Forward call:
Static call is performed in the following ways: self:, parent:, static: And forward_static_call ().
Non-forward call:
Specify the static call of the Class Name (for example, Foo: foo ())
Non-static call (for example, $ foo-> foo ())
2. Working Principle of static binding later
Principle: stores the class name in the previous non-forwarded call. This means that when we call a static call of a forwarding call, the actual called class is the previous non-forwarding call class.
Example Analysis:
<? Phpclass 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 (); // after the test () API is called, the class stored in "last non-forwarded call" is named C ** // The class name stored in "last non-forwarded call" is named C * public static function test () {* A: foo (); // non-forwarded call. After calling foo (), the class stored in "last non-forwarded call" is named, then, execute the code A: foo () and convert it to 0-0 * parent: foo (); // forward the call. After calling foo, the class stored in "last non-forwarding call" is named C. The parent here is parsed as A and transferred to 1-0 * self: foo (); // The forwarding call, after calling foo (), the class stored in "last non-forwarded call" is named C. Here, self is resolved to B, convert 2-0 *} **** 0-0 * // The Name Of The class stored in the previous non-forwarding call is A * public static function foo () {* static:: who (); // forward call. Because the class stored in the previous non-forward call is named A, the actual code A: who () is executed (), that is, static indicates A. After calling who (), the class name stored in "last non-forwarding call" is still, therefore, print "A" *} ** 1-0 * // The Name Of The class stored in "last non-forwarded call" is C * public static function foo () {* static:: who (); // forward call. Because the class stored in the previous non-forward call is named C, the code C: who () is actually executed (), that is, static indicates C. After calling who (), the class name stored in "last non-forwarding call" is still C, therefore, print "C" *} ** 2-0 * // The Name Of The class stored in "last non-forwarded call" is C * public static function foo () {* static:: who (); // forward call. Because the class stored in the previous non-forward call is named C, the code C: who () is actually executed (), that is, static indicates C. After calling who (), the class name stored in "last non-forwarding call" is still C, therefore, the final result is: A: foo () AAparent: foo () ACself: foo () AC.
3. More static binding examples
A) Comparison between Self, Parent and Static
<? Phpclass 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 _ CIA SS __;}$ apple = new Apple (); echo $ apple-> selfname (). "\ n"; echo $ apple-> parentname (). "\ n"; echo $ apple-> staticname ();?> Running result: MangoOrangeApple
B) Use forward_static_call ()
<? Phpclass 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" ;}?> Running result: Orange isOrange is my favorite fruitApple is my father's favorite fruit
C) use get_called_class ()
<? Phpclass Mango {static public function fruit () {echo get_called_class (). "\ n" ;}} class Orange extends Mango {//} Mango: fruit (); Orange: fruit () ;?> Running result: MangoOrange
Application
As mentioned above, the purpose of introducing static binding is to reference the class for static calling within the inheritance scope.
Therefore, you can use static binding later to solve the problem of Singleton inheritance.
Let's take a look at the situation of using self:
<? Php // new self returns A as A singleton. 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 ($ ); var_dump ($ B); var_dump ($ c); running result: 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 ){}
The preceding example shows that the same object of Class A is obtained through self instantiation.
Let's take a look at the results of using static.
<? Php // new static obtains the following Singleton values: D, E, and 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 ); running result: 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 ){}
We can see that using static can solve the problem of Singleton inheritance during self.