In depth explanation of PHP delayed static binding

  • 2021-09-16 06:23:06
  • OfStack

Preface

The so-called delayed static binding, as its name implies, is delayed when the binding of the left part of the:: symbol is called statically, that is, it is no longer resolved to define the class where the current method is located, but calculated at actual runtime. This article mainly introduces the related content about PHP delayed static binding. Let's not say much below. Let's take a look at the detailed introduction.

Smell the bad smell

At this time, looking at the PHP code in the background of the project, I saw a piece of code similar to the following, and I took it out:


<?php
 class DBHandler {
  function get() {}
 }

 class MySQLHandler extends DBHandler {
  //  Here 1 A create
  public static function create() {
   echo "MySQL";
   return new self();
  }
  public function get() {
   echo "MySQL get()";
  }
 }

 class MemcachedHandler extends DBHandler {
  //  There are again here 1 A create
  public static function create() {
   echo "Memcached";
   return new self();
  }
  public function get() {
   echo "Memcached get";
  }
 }

 function get(DBHandler $handler) {
  $handler->get();
 }
 $dbHandler = MySQLHandler::create();
 get($dbHandler);
?>

Do you smell bad code? As you can see, in both MySQLHandler and MemcachedHandler classes, there is an create function. If I get rid of my output statements, I find that they are 1 module 1, which is code redundancy. Yes, code refactoring is required.

Make a simple refactoring

Code refactoring is everywhere, and if you want to, if you feel that there is improvement, you need to hit the keyboard and start working. Come on, refactor the above code, as follows:


<?php
 class DBHandler {
  public static function create() {
   echo "create";
   return new self();
  }
  function get() {}
 }

 class MySQLHandler extends DBHandler {
  public function get() {
   echo "MySQL get()";
  }
 }

 class MemcachedHandler extends DBHandler {
  public function get() {
   echo "Memcached get";
  }
 }

 function get(DBHandler $handler) {
  $handler->get();
 }
 $dbHandler = MySQLHandler::create();
 get($dbHandler);
?>

Moving the create function to the DBHandler class looks good, with at least one lump of bad code missing.

Seems to be wrong

Run 1, only to find that it didn't print out what we expected MySQL get()  . What happened? This means that the get function of MySQLHandler is not called, but the code clearly calls it, which means that, new self() There is something wrong with this code. What's wrong with this? This brings us to the focus of today's summary-delayed static binding.

Deferred static binding

Delayed static binding was introduced after PHP 5.3. Look at the following code again:


<?php
 class A {
  public static function who() {
   echo __CLASS__;
  }
  public static function test() {
   self::who();
  }
 }

 class B extends A {
  public static function who() {
   echo __CLASS__;
  }
 }
 B::test();
?>

The above code outputs A, but I want it to output B, which is the problem. This is also the limitation of self and __CLASS__. A static reference to the current class using self:: or __CLASS__, depending on the class in which the current method is defined. Therefore, this explains why the above code outputs A. But what if we need to output B? You can do this:


<?php
 class A {
  public static function who() {
   echo __CLASS__;
  }
  public static function test() {
   static::who(); //  There is a change here, and the late static binding starts here 
  }
 }

 class B extends A {
  public static function who() {
   echo __CLASS__;
  }
 }
 B::test();
?>

Late static binding would have circumvented the restriction by introducing a new keyword to represent the class originally called at runtime. Simply put, this keyword enables you to refer to B instead of A when you call test () in the above example. Eventually it was decided not to introduce new keywords, but to use the static keyword that had been reserved.

This is the root of late static binding-an alternative use of the static keyword. For the example at the beginning of Article 1, you can change it like this:


return new static(); //  Change here, late static binding 

This use of late static binding makes it easy to use PHP to implement the design pattern in 23.

Summarize

It is a very simple knowledge point, but it is very useful. To sum up, I checked some information and added 1 knowledge point. One reviews the old to know the new. Well, I hope it will be helpful to everyone. If you have any suggestions to make my article better, don't hesitate to put them forward. I need your help.


Related articles: