Back to Home

Late static binding in PHP (Part II: Practice)

php · late static binding

Late static binding in PHP (Part II: Practice)

    phpRead the first part here .

    Now let's get to practice. The most indicative example of using LSB, in my opinion, is the case when you have a set of classes that perform similar actions. In terms of web development, we often encounter such problems when accessing database tables, especially in ORM systems. All your objects for working with tables will be similar in essence, but at the same time they will have their own functionality (and, accordingly, their subclasses).

    Suppose we have a Storable class in our system that implements (you guessed it) (Translator's note: I didn’t guess :)) the Storable pattern. We define classes that inherit from the Storable class and specify table names in the constructors. Here's what it looks like:

      class ArticleEntry extends Storable {
    	  public function __construct ($ id = null) {
    		  if (! is_null ($ id)) {
    			  $ id = array ('id' => $ id);
    		  }
    		  parent :: __ construct ('articleEntry', '*', $ id);
    	  }
      }
      // output the text of the entry:
      $ entry = new ArticleEntry (10); // Fetch an entry from the articleEntry table for which id = 10;
      echo $ entry-> html ('articleBody'); // output the body of the loaded entry
      // update the record:
      $ entry ['ts'] = time (); // set the time to NOW
      $ entry-> save (); // Update the record
    


    You can skip the details of the constructor, it is provided only for you to imagine how the Storable class works . As you already understood, this will save us a little time and will not spend it on such trifles as simple SELECT , INSERT and UPDATE queries .

    In our system, in addition to the main table of the Article ( ArticleEntry), several more tables will be used that contain meta-data (in many-to-one relationships), for example: tags, attachments. I also need an easy way to delete data from sub-tables before updating the data in the main table (it’s easier to delete the meta-data and recreate it than worry about data synchronization). So, to simulate the code closest to the database schema, I settled on this implementation:

      abstract class ArticleEntryAbstract extends Storable {
    	  public function __construct ($ table, $ id = null) {
    		  if (! is_null ($ id)) {
    			  $ id = array ('id' => $ id);
    		  }
    		  parent :: __ construct ($ table, '*', $ id);
    	  }
    	  public function purge () {
    		  $ s = $ this-> db-> prepare ('DELETE FROM'. $ this-> tableName. 'WHERE pulseEntryId =?');
    		  $ s-> execute (array ($ this-> data ['entryId']));
    	  }
      }
    


    All focus in the purge () method . The $ this-> tableName property is the protected property that we received from the Storable class . Here is a usage example:

      class ArticleEntryAttachment extends ArticleEntryAbstract {
    	  public function __construct ($ id = null) {
    		  parent :: __ construct ('articleEntryAttachment', $ id);
    	  }
      }
    


    I have a bunch of such small classes for working with metadata tables. Unfortunately, since our system uses PHP version 5.2, I could not use the LSB functionality described in the first part of the article. And to delete the meta data, I have to write:

      $ attach = new ArticleEntryAttachment (10); // SELECTS from the articleEntryAttachment table WHERE entryId = 10
      $ attach-> purge ();
    


    If you look above, as determined by purge The () , you'll see that tableName it receives from the class Storable, which gets him out of the descendant class designers. Besides this trivial (but absolutely necessary) data, as well as getting the database object in $ this-> db , we did not achieve anything by creating an object of the articleentryattachment class . The code would be much clearer and cleaner (and certainly more efficient) if the purge () method could be called statically. Consider the following code:

      abstract class ArticleEntryAbstract extends Storable {
    	  public function __construct ($ table, $ id = null) {
    		  if (! is_null ($ id)) {
    			  $ id = array ('id' => $ id);
    		  }
    		  parent :: __ construct (static :: TABLE_NAME, '*', $ id);
    	  }
    	  static function purge ($ entryId) {
    		  $ db = Db :: get (); // get the singleton database
    		  $ s = $ db-> prepare ('DELETE FROM'. static :: TABLE_NAME. 'WHERE pulseEntryId =?');
    		  $ s-> execute (array ($ entryId));
    	  }
      }
      class ArticleEntryAttachment extends ArticleEntryAbstract {
    	  const TABLE_NAME = 'articleAttachment';
      }
    


    The first thing I hope you have noticed is that ArticleEntryAttachment has become a lot easier. Now there is no need to redefine the constructor for subclasses, because the constructor of the parent class is self-sufficient. And now you can use the purge () method (using LSB):

    ArticleEntryAttachment :: purge (10);
    


    Since, now purge () can get the name of the table, which is determined at runtime, we can make it static. As a result, the code is cleaner, execution is more efficient, support (for example, adding new subclasses) is nonsense, because redundancy is completely removed. Thanks to the PHP developers for making this possible!

    The manual also discusses other ways to use the LSB, including the use of constants __CLASS__ , so do not forget to visit php.net

    to Via Denis.in.ua: Late static binding in PHP (Part II: Practice)

    Original: The Late the Binding the Static: a Practical example

    Read Next