Properly implementing Polymorphism

One of the most powerful parts of the object oriented programming paradigm is polymorphism. Child classes may inherit then modify the behaviors of their parents. Through the inheritance tree of the classes we can move from the abstract to the specific. But it is also something I frequently see done… poorly… even in high level and popular applications (not going to name drop). You know it’s being done poorly when you see this


class foo {
  public function save() {
  /*
   * A lot of steps
   */
    $this->presave();
    $this->dosave();
    $this->postsave();
   /*
    * A lot more steps
    */
    return;
  }

  protected function presave(){}
  protected function postsave(){}

}

The idea is that the empty functions get defined later. This is the WRONG way to do this (I should know because I did it the wrong way for a long time).

For polymorphism to be effective, flexible and powerful, you must follow a doctrine of “for each method, one and only one task”. In other words, the above should look like this.


class foo {
  public function save() {
    $this->step1();
    $this->step2();
    $this->step3();
    $this->step4();
    $this->doSave();
    $this->step5();
    $this->step6();
    $this->step7();
  }
}

In live code each of the step functions will have a descriptive name of course - I’m just rattling off an example here. Now that each step of the save process is it’s own method we can modify the process at any step we choose by extending the function at the step we want to interrupt, do our interrupt action, then call the parent action.

So if you find yourself wanting to write an empty method in a concrete class that gets called as a ‘hook’ - its almost certain that the function calling that hook is doing too much and needs to be broken down into other functions. Note that this doesn’t apply to empty methods in abstract classes - they serve a different purpose altogether by requiring uncertain behavior to be defined before completion.

Hi Michael,

Great that you are bringing forth proper OOP ideas (as you have always done). It occurs to me that many people may not understand why using polymorphism can be a good idea and examples of the power of it. I won’t have time to knock together a simple example today. But I think a simple example might help others.

In any regards, thanks for doing this and keep it going :slight_smile:

Regards,
Steve

An example would definitely help. I’m sure if one knows what you are talking about, it’s all clear. But me, I don’t see much difference in the two pieces of code you wrote. The second has some more ‘calls’, and no protected functions (are they supposed not to be there, or did you just not write them to keep the example short?), but it’s not clear to me why the first is the wrong way, and the second the correct way.

If you could elaborate some more, I would be very grateful. I have a basic knowledge of OOP, and am trying to get deeper into it, so I’m very interested in posts like these.

Hi guido2004,
I am trying to think of a good subject to use to simply illustrate the power behind this pattern. To often the example on the web use Automobiles or Animals to demonstrate, but I am going to find something that actually affects PHP authors so they can see the difference when they think of how the do this when writing procedural code. The subject need not to get people mired in details so that it remains clear. I will have it by morning (9:56 PM Eastern Time now), so around 7:00 AM tomorrow I will lay it out and hopefully will do it Justice :slight_smile:

Glad you are looking to grow in this area! I am sure there are a good number of people that could benefit from moving more of their code to OOP, but just need a non-intimidating approach and good reasons to see why they should switch; too often OOP developers loose sight that procedural programming is quite different and at the same time often very effective. The better approach would to see how OOP can better structure and reduce code and promote reuse; while this is possible also in procedural programming there are some things that can be done with OOP that are not possible via procedural methods.

Regards,
Steve

Hi Steve, I already use OOP, and I even know what polymorphism is (in theory). What isn’t clear to me is the point @Michael_Morris; is trying to make with the two pieces of code he posted. An example to explain why the first way is wrong, and the second is good, would be great.
And since Michael says he has done it the wrong way for a long time, I was hoping he could take a case where he did it wrong, explain how he did it (wrong), why it is wrong, how he would do it today (right) and why it is right.

Ok saves me doing an example :wink:

Hey, if you can give me an example to clarify Michael’s post, don’t hesitate! :smiley:

I’ll construct something more elaborate this evening.

I think the illustration/example does not properly present @Michael_Morris; actual intent.
That example, although you are demonstrating Polymorphism, demonstrates a very ‘procedural’ process. It is very linear and does not [necessarily] benefit from OOP.

I stand with @guido2004; in that, because it is procedural, there is no difference between the two code snippets.

This is a very interesting discussion - please don’t misunderstand my statement as a criticism.

This was the polymorphic example I was going to post this morning. Notice the displayHTMLElement function is completely agnostic to what type of HTML element is being processed.

Copy all this code into a php file and run it:

<?php 
Interface IHtml{  
  public function showHTML(); 
  public function setText($text);
}
class HtmlElement implements IHtml{
   public function showHTML(){}  
   public function setText($text){}
}
class H1 extends HtmlElement{ 
  protected $h1;  
  public function setText($text){    
    $this->h1 = "<h1>$text</h1>";  
 }  
 public function showHTML(){    
   echo $this->h1;  }
 }

 class Paragraph extends HtmlElement{ 
   protected $p;  
   public function setText($text){    
     $this->p = "<p>$text</p>";  
   }  
   public function showHTML(){    
     echo $this->p;  
  }
}

function displayHTMLElement(HtmlElement $obj){  
  $obj->showHTML();
}

$pageH1 = new H1();
$pageH1->setText('This is an example of polymorphism in PHP');

$aParagraph = new Paragraph();
$aParagraph->setText('This is a paragraph of text. I should have use lores Impsum? Oh Well?');

$bParagraph = new Paragraph();
$bParagraph->setText('This is another paragraph of text. You get the point!');

$page = array(  
  $pageH1  
  , $aParagraph  
  , $bParagraph
);

foreach($page as $htmlElementObj){  
  displayHTMLElement($htmlElementObj);
}
?>

Obviously this is simplified for the purposes of example.

Polymorphism in PHP basically means that a single class, method or variable name may present itself in many different forms.

We know that every class that inherits from HtmlElement baseclass, automatically inherits the showHTML(), and setText() methods. We override the showHTML() and setText() methods in every subclass of HtmlElement. Our subclass objects know what to do when their showHTML() method is being called, without us having to worry of what type our subclass object is. This pattern is often used to replace bad or difficult switch code.

Feel free to tear it apart if need be :slight_smile:

Regards,
Steve

Math is the parent of computing, so let us turn to it to provide the abstraction we need.



class A {
  protected $a;
  protected $b;

  public function __construct( $a, $b ) {
    $this->a = $a;
    $this->b = $b;
  }

  public function sum() {
    return $this->a + $this->b;
  }
}

This demonstrates two principles. First, constructors should only be used to create a ready state. They should never perform other operations. Now, let’s extend the class to handle division


class B extends A {
  public function divide() {
    return $a / $b;
  }
}

See a problem? If $b == 0, we’ll get E_USER_ERROR. So we could correct our function for this.


class B extends A {
  public function divide() {
    if ($this->b == 0 ) {
      echo 'undefined';
      return null;
    } else {
      return $this->a / $this->b;
    }
  }
}

But suppose we have a formula where, when $b = 0, we should return zero. With the example above we can to overwrite the entire function like so


class C extends B {
  public function divide() {
    return ($this->b == 0) ? 0 : $this->a / $this->b;
  }
}

Got the basics, good. Let’s make it complex


class A extends ArrayObject {
  public function sum() {
    $r = 0;

    foreach ($this as $v) {
      $r += $v;
    }

    return $r;
  }

  public function product() {
    $r = 1;

    foreach ($this as $v) {
      $r *= $v;
    }

    return $r;
  }
}

We will start with array object because we want array-like behaviors. If we make an ‘A’ we can address it like an array like so.


$a = new A(array( 1, 2, 3, 4, 5, 6 ));
echo $a->sum(); // 21
$a[] = 9;
echo $a->sum(); // 30

Now we will make another child that needs a product of all non-zero.


class B extends A {
  public function productOfAllNonZero() {
    $r = 1;
    foreach ( $this as $v ) {
      if ($v != 0 ) {
       $r *= $v;
      }
    }

    return $r;
  }
}

Note that this repeats the product function almost verbatim, but adds another step. This is inefficient. We can refactor though.


class A extends ArrayObject {
  public function sum() {
    return $this->doSum($this);
  }

  protected function doSum( $a ) {
    $r = 0;

    foreach ($a as $v) {
      $r += $v;
    }

    return $r;
  }

  public function product() {
    return $this->doProduct($this);
  }

  public function doProduct( $a ) {
    $r = 1;

    foreach ($a as $v) {
      $r *= $v;
    }

    return $r;
  }
}

And now the child class is made simpler.


class B extends A {
  public function productOfAllNonZero() {
    return $this->doProduct($this->filterZeros( $this ));
  }

  protected function filterZeros( $a ) {
    $r = array();

    /*
     * Yes, array_filter() is quicker, but less illustrative of process.
     * That, and I'm not sure array_filter works with array objects and
     * not inclined to look that up right now.
     */
    foreach ( $a as $v ) {
      if ($v != 0) {
        $r[] = $v;
      }
    }

    return $r;
  }
}

Now, let’s create a class that has a method with a lot going on.


class C extends B {
  protected $answer = 0;

  const THE_MEANING_OF_LIFE = 42;
  // That's what Douglas Adam's says.

  public function foo() {
    $this->productOfAllNonZero();
    $this->subtractEverything();
    $this->addTheMeaningOfLife();
    $this->square();
    $this->addEverything();
    return $this->answer;
  }

  protected function productOfAllNonZero() {
    $this->answer = parent::productOfAllNonZero();
  }

  protected function subtractEverything() {
    $this->answer -= $this->doSum($this);
  }

  protected function addTheMeaningOfLife() {
    $this->answer += self::THE_MEANING_OF_LIFE;
  }

  protected function addEverything() {
    $this->answer += $this->doSum($this);
  }
}

Now suppose we need to a square operation after adding the meaning of life.


class D extends C {
  protected function addTheMeaningOfLife() {
    parent::addTheMeaningOfLife();

    $this->answer = pow($this->answer, 2);
  }
}

And I can go on, but this sufficiently demonstrates how to make granular functions. One word of warning which should go without saying - one letter variables and class names are ok when dealing with the utterly abstract of math. Do not use them in live code.

@Michael Morris

To say that preX(), postX(), methods in your first example is “wrong” would be over the top. There is always a trade off to everything.

You can still make great use of pre, post and save (or commit), like so:


<?php

class Example {
  // a collection of pre step objects to do before calling save
  private $pre = array();

  // a collection of post step objects to do after save is called
  private $post = array();

  public function all() {
    $this->pre();
    $this->save();
    $this->post();
  }

  public function pre() {
    foreach ($this->pre as $object) {
      //do something
    }
  }

  public function save() {
    //commit
  }

  public function post() {
    foreach ($this->post as $object) {
      //do something
    }
  }
}

The Pre/Post objects encapsulate the behavior. It doesn’t affect the class and each method never does more than one thing.

PHP does allow you to have a member and method with the same name. In my opinion, that’s a major Pain In The Ass and extremely bad practice because very few languages will let you do that. The language used in concert with PHP -> Javascript, doesn’t permit such behavior. It leads to unmaintainable byzantine crap code - don’t do it.

The possibility of using traits, closures and object composition to further refine object behavior is out of scope, but my argument remains the same. This is correct.


class A {
  public function save() {
    // save action only
  }
}
class B extends A {
  public function save() {
    // more actions
    parent::save();
  }
}

This is not correct.


class A {
  public function save() {
    $this->preSave();
    // save method
  }
}

class B extends A {
  protected function presave() {
     // more actions
  }
}

YMMV, but I see the use of hooks amateurism. Yes it works, but it isn’t elegant and it is FAR more limited than breaking the functions down into one action each. In that event you can effectively put your hook anywhere you want it to be and have it do whatever you want.

@Michael Morris

Nice example, several concepts well explained, thanks.

Though In your first example that started this thread you mentioned about overriding empty methods in the ‘right way’ but in your most recent example you aptly demonstrate granularity (and also why some people favour composition over inheritance :wink: ) but for some of us it is still hard to see the correlation to your first example.

In your first example ‘The proper way’, if we related to your second example, would it be that Class C extends B in your most recent example and the methods were either inherited or overridden in Class B extend A with the methods in Class A? The point being keeping each class very focused and inheriting rather than trying to jam all tasks into a singular class?

Regards,
Steve

Object composition solves different problems than inheritance does. Both have advantages and disadvantages. The goal is to recognize which of the two best addresses the problem at hand and deploy the correct one.

As to class length, a class should be as long as it needs to be, as short as it can possibly be, and no longer. If in doubt err in favor of brevity.

Agreed, but I am still unclear what your first post was illustrating about overriding empty methods. Maybe I am the slow one in the crowd? I like the fact that you were recommending the right versus wrong way but don’t understand why it is the right way.

Regards,
Steve

Or if you want to run the parent’s thread by only inserting a single method to be run after/before one of the defaults…

(Yes, it’s messy. Yes, I was bored):

<?phpclass ProcessManager extends Process{	protected $Processes = array();	public function __Construct(){			}	public function hasFinished(){		return 0 == count($this->getPossibleTasks());	}	public function getPossibleTasks(){		$Tasks = array();		foreach($this->getRemainingTasks() as $Name => $Process){			if($Process->isPossible()){				$Tasks[$Name] = $Process;			}		}		return $Tasks;	}	public function getRemainingTasks(){		$Processes = array();		foreach($this->Processes as $Name => $Process){			if(!$Process->hasFinished()){				$Processes[$Name] = $Process;			}		}		return $Processes;	}	public function countPossibleTasks(){		return count($this->getPossibleTasks());	}	public function countRemainingTasks(){		return count($this->getRemainingTasks());	}	public function getProcess($Name){		if($Name instanceof Process){			return $Name;		}		return array_key_exists($Name, $this->Processes) ? $this->Processes[$Name] : false;	}	public function addProcess($Name, $Callback, $Arguments = array()){		if(!is_array($Arguments)){			$Arguments = array($Arguments);		}		$this->Processes[$Name] = $Process = new Process($this, $Callback, $Arguments);		return $Process;	}	public function step(){		foreach($this->getPossibleTasks() as $Task){			echo "<p>" . $Task->run() . "</p>";		}	}	public function run(){		while($this->countPossibleTasks() > 0){			$this->step();		}		if($this->countRemainingTasks() > 0){			echo "Not all tasks could be run due to a structural error";		}	}}class Process{	protected $Before = array();	protected $Dependencies = array();	protected $Callback;	protected $Arguments = array();	protected $Status = 0;	protected $Manager;	function __Construct(ProcessManager $Manager, $Callback, array $Arguments = array()){		$this->Manager = $Manager;		$this->Callback = $Callback;		$this->Arguments = $Arguments;	}	protected function hasFinished(){		return $this->Status == 1;	}	public function equals(Process $Process){		return $Process->Callback == $Callback;	}	public function isPossible(){		foreach($this->Dependencies as $Task){			if(!$Task->hasFinished()){				return false;			}		}		return true;	}	public function ensureAfter(){		$Arguments = func_get_args();		if(count($Arguments) != 1){			foreach($Arguments as $Argument){				ensureAfter($Argument);			}			return $this;		}		$Name = $Arguments[0];		$Dependency = $this->Manager->getProcess($Name);		if($Dependency !== false){			$this->Dependencies[] = $Dependency;		}		return $this;	}	public function ensureBefore(){		$Arguments = func_get_args();		if(count($Arguments) != 1){			foreach($Arguments as $Argument){				ensureAfter($Argument);			}			return $this;		}		$Name = $Arguments[0];		$Child = $this->Manager->getProcess($Name);		if($Child !== false){			$Child->ensureAfter($this);		}		return $this;	}	public function run(){		$this->Status = 1;		return call_user_func_array($this->Callback, $this->Arguments);	}}
class SomeData{	protected $Something = '';	public function setSomething($Value){		$this->Something = $Value;	}	public function getSomething(){		return $this->Something;	}}
function setSomeData(SomeData $Data){	$Data->setSomething("This is my data");	return 'I set the data to "This is my data"';}function outputSomeData(SomeData $Data){	$Text = $Data->getSomething('This is my data');	return 'I retrieved the data, it is: "' . $Text . '"';}function somethingEntirelyDifferent(){	return 'I dont need the data';}$Data = new SomeData;$Manager = new ProcessManager;$Manager->addProcess('f2', 'outputSomeData', $Data);$Manager->addProcess('f1', 'setSomeData', $Data)->ensureBefore('f2');$Manager->addProcess('f3', 'somethingEntirelyDifferent');$Manager->run();

@Jake Arkinstall

Code cleaned up for all the enjoy:

class ProcessManager extends Process{    
  protected $Processes = array();    
  public function __Construct(){ }    
  public function hasFinished(){
    return 0 == count($this->getPossibleTasks());
  }    
  public function getPossibleTasks(){
    $Tasks = array();        
    foreach($this->getRemainingTasks() as $Name => $Process){
      if($Process->isPossible()){
        $Tasks[$Name] = $Process;
      }        
    }
    return $Tasks;    
  }
  public function getRemainingTasks(){
    $Processes = array();        
    foreach($this->Processes as $Name => $Process){
      if(!$Process->hasFinished()){ 
        $Processes[$Name] = $Process;
      }
    }
    return $Processes;
  }    
  public function countPossibleTasks(){
    return count($this->getPossibleTasks());
  }
  public function countRemainingTasks(){
    return count($this->getRemainingTasks());
  }    
  public function getProcess($Name){
    if($Name instanceof Process){
      return $Name;
    }
    return array_key_exists($Name, $this->Processes) ? $this->Processes[$Name] : false;    
  }
  public function addProcess($Name, $Callback, $Arguments = array()){
    if(!is_array($Arguments)){
      $Arguments = array($Arguments);
    }
    $this->Processes[$Name] = $Process = new Process($this, $Callback, $Arguments);
    return $Process;    
  }
  public function step(){
    foreach($this->getPossibleTasks() as $Task){
      echo "<p>" . $Task->run() . "</p>";
    }
  }
  public function run(){
    while($this->countPossibleTasks() > 0){
      $this->step();
    }
    if($this->countRemainingTasks() > 0){
      echo "Not all tasks could be run due to a structural error";
    }    
  }
}
class Process{    
  protected $Before = array();    
  protected $Dependencies = array();    
  protected $Callback;    
  protected $Arguments = array();    
  protected $Status = 0;    
  protected $Manager;    
  function __Construct(ProcessManager $Manager, $Callback, array $Arguments = array()){
    $this->Manager = $Manager;
    $this->Callback = $Callback;
    $this->Arguments = $Arguments;
  }    
  protected function hasFinished(){
    return $this->Status == 1;
  }
  public function equals(Process $Process){
    return $Process->Callback == $Callback;    
  }    public function isPossible(){
    foreach($this->Dependencies as $Task){
      if(!$Task->hasFinished()){
        return false;
      }        
    }        
    return true;    
  }    
  public function ensureAfter(){        
    $Arguments = func_get_args();        
    if(count($Arguments) != 1){            
      foreach($Arguments as $Argument){                
        ensureAfter($Argument);            
      }            
      return $this;        
    }        
    $Name = $Arguments[0];        
    $Dependency = $this->Manager->getProcess($Name);        
    if($Dependency !== false){
      $this->Dependencies[] = $Dependency;        
    }        
    return $this;    
  }    
  public function ensureBefore(){        
    $Arguments = func_get_args();        
    if(count($Arguments) != 1){            
      foreach($Arguments as $Argument){                
        ensureAfter($Argument);
      }            
      return $this;        
    }        
    $Name = $Arguments[0];        
    $Child = $this->Manager->getProcess($Name);        
    if($Child !== false){            
      $Child->ensureAfter($this);        
    }        
    return $this;    
  }    
  public function run(){        
    $this->Status = 1;        
    return call_user_func_array($this->Callback, $this->Arguments);  
  }
}
class SomeData{
  protected $Something = '';    
  public function setSomething($Value){        
    $this->Something = $Value;    
  }    
  public function getSomething(){        
    return $this->Something;    
  }
}
function setSomeData(SomeData $Data){    
  $Data->setSomething("This is my data");    
  return 'I set the data to "This is my data"';
}
  
function outputSomeData(SomeData $Data){    
  $Text = $Data->getSomething('This is my data');    
  return 'I retrieved the data, it is: "' . $Text . '"';
}
function somethingEntirelyDifferent(){
  return 'I dont need the data';}
  $Data = new SomeData;$Manager = new ProcessManager;
  $Manager->addProcess('f2', 'outputSomeData', $Data);
  $Manager->addProcess('f1', 'setSomeData', $Data)->ensureBefore('f2');
  $Manager->addProcess('f3', 'somethingEntirelyDifferent');$Manager->run
}

That makes two of us :slight_smile:

It would be very interesting to see some examples of problems that are best solved by object composition, and some that are best solved by inheritance. I know I’m asking much, but hey, I can try :wink:

And yes, I’m trying to keep things on my level. For example, I understand Jake’s code example (from a purely technical point of view), but I have no idea what he was trying to show us from a theoratical point of view. Without some explanation, I’m lost.

You shouldn’t need to produce empty placeholder methods which may never need to be populated. It just doesn’t look right. Also, there is a break between the external facing API and the internal API. For example, going back to the original example…


class A {

  public function save() {
   /*
    * code before save
    */
   $this->presave();
   /*
    * code doing save
    */
   $this->postsave();
   /*
    * code after post save
    */
  }
}

This is less efficient, in my mind, than


class A {

  public function save() {
    $this->precommit();
    $this->commit();
    $this->postcommit();
  }

  protected function precommit() {
   /*
    * code before save
    */
  }

  protected function commit() {
   /*
    * code doing save
    */
  }

  protected function postcommit() {
   /*
    * code after post save
    */
  }
}

The former method, the one I label as incorrect, allows for 2 possible hook points and 2 functions which may remain unused. The later method allows for 6 hook points overall, though effectively 4 hooks since there is no operative difference between hooking in at the end of precommit and hooking to the start of commit.

More important than the choice to do hooks or not is this - the more your function does, the more likely you will need to alter the course of its operation in the future. That’s the primary reason to keep the scope of the function small. The same applies to classes - the larger they are the more likely they will need modification.

Avoiding hooks encourages code granularity. Polymorphism, whether achieved through inheritance or by composition, needs the elements of the code to be as granular as possible.