Posted by on in iDevelop, PHP | 3 comments

What are abstract properties? There are abstract methods but the notion of an abstract property seems a bit ridiculous. Why so, you might ask! Well, the thing is, methods are declared & defined (not necessarily at same time). So you can declare a method without actually defining it (ie., no body, no set of commands which it will execute) and the same can be defined at a later stage. But there is no such thing as defining a property of a class; properties are always declared as containers of data which reserve a space in memory on class initialization.

As I was re-factoring data validation service in a project I’m working on (will open source it once first working draft is ready), I thought about making the $rules property abstract. But then I realized the absurdity of my thought and the fact that PHP does not have such a concept, not even like what C# has. From what little I know of C#, it has a concept of abstract properties which are compiled into functions by the compiler. So if I were to do this:

  1. public abstract class Foo {
  2.     //abstract property, only declaring a getter
  3.     public abstract string Bar {
  4.         get;
  5.     }
  6. }

then Bar would eventually be compiled as getBar() (would’ve had setBar() too if we had declared a setter). So while you think you’re using abstract properties, its just pseudo code for accessors and mutators (getters and setters if you prefer). To my knowledge, Java doesn’t have the concept of abstract properties. I think I read about Smalltalk having something similar but I’m not sure and we digress, so back to PHP if you will. 🙂

So why did I think of implementing abstract property in my validation service? The way my validation service is designed, it has a base abstract class which has only one method, validate(), which accepts data and an array containing validation rules. Now each entity in the application has its own corresponding validation service which extends this base class and defines a set of validation rules unique to the entity it represents. To keep the naming consistent, its better to have $rules property in all the children of the base class and this is where the notion of an abstract property seems plausible.

So how did I go about it? With a little bit of hocus pocus I should say:

php
…ces/Validation/Validator.php

  1. abstract class Validator {
  2.  
  3.     /**
  4.      * @var array An array containing names and types of abstract properties that must be implemented in child classes
  5.      */
  6.     private $_abstract_properties = array(
  7.         'array' => array(
  8.             'rules',
  9.         ),
  10.     );
  11.  
  12.     final public function __construct() {
  13.         $this->_abstract_properties_existence_enforcer();
  14.     }
  15.  
  16.     final protected function _abstract_properties_existence_enforcer() {
  17.         //check if the child has defined the abstract properties or not
  18.         $current_child = get_class( $this );
  19.  
  20.         foreach ( $this->_abstract_properties as $type => $properties ) {
  21.             $count = count( $properties );
  22.  
  23.             for ( $i = 0; $i < $count; $i++ ) {
  24.                 if ( property_exists( $this, $properties&#91; $i ] ) && strtolower( gettype( $this->$properties[ $i ] ) ) == $type ) {
  25.                     continue;
  26.                 }
  27.  
  28.                 //property does not exist
  29.                 $error = $current_child . ' class must define $' . $properties[ $i ] . ' property as ' . $type;
  30.  
  31.                 throw new \LogicException( $error );
  32.             }
  33.         }
  34.  
  35.         unset( $error, $current_child );
  36.     }
  37.  
  38.     public function validate( array $data ) {
  39.         //We know $this->rules exists because we have declared it as an abstract property
  40.         //above which all child classes need to define as an array
  41.  
  42.         return Vendor\Library\Service\Validation::make( $data, $this->rules );
  43.     }
  44.  
  45. }

Any class that now extends Validator would need to declare properties of same type as set in $_abstract_properties. So for example, if we need an AuthValidator then it would be like:

php
…Validation/AuthValidator.php

  1. class AuthValidator extends Validator {
  2.  
  3.     /**
  4.      * @var array An array containing validation rules for authentication
  5.      */
  6.     public $rules = array(
  7.         'email' => array( 'required', 'email', 'exists:users' ),
  8.         'password' => array( 'required', 'alphanumeric_special', 'min:10' ),
  9.     );
  10.  
  11. }

And to use it all we need to do is:

php
…rs/UserSessionController.php

  1. class UserSessionController extends BaseController {
  2.  
  3.     public function store() {
  4.         $validator = new Services\Validation\AuthValidator;
  5.  
  6.         try {
  7.             $validator->validate( $_POST );
  8.         } catch ( \ValidationException $e ) {
  9.             //invalid data, handle response accordingly
  10.         }
  11.     }
  12.  
  13. }

I’ve set the constructor to be final in Validator as the children will have no need to have their own constructors but this is not mandatory for all implementations. If in your implementation child classes have their own constructors then the constructor here in base class shouldn’t be final. In that case, one thing to remember will be to either put in parent::__construct() call in child constructor(s) before anything else or call _abstract_properties_existence_enforcer(). Its a bit of a hassle and in my opinion implementing a Singleton or Factory pattern (as per your need) is better in such a case which would avoid the oversight of failing to call _abstract_properties_existence_enforcer().

 
So there you have it, the notion of abstract properties in PHP realized. 😉