Home arrow PHP arrow Page 3 - PHP Liskov Substitution Principle

Violating the Liskov Substitution Principle - PHP

This PHP programming tutorial focuses on how to utilize the Liskov Substitution Principle (LSP) to develop better OOP applications.

TABLE OF CONTENTS:
  1. PHP Liskov Substitution Principle
  2. Implementing a Composite View Rendering Layer
  3. Violating the Liskov Substitution Principle
By: Alejandro Gervasio
Rating: starstarstarstarstar / 1
June 29, 2011

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

Breaking up the law: violating the Liskov Substitution Principle

As I was saying before, once I finished speaking with my eager client, I decided to construct a simple class that allowed him to build sets of ready-to-use web page layouts, which he could use in different shell scripts. So, after thinking about it for a while, I came up with the following layout builder:  

(App/Utility/LayoutBuilder.php)<?phpnamespace App\Utility;
use App\View;class LayoutBuilder
{
    protected $_views = array();
   
    /**
     * Attach a view
     */
    public function attachView($key, View\AbstractView $view)
    {
        if (isset($key)) {
            $this->_views[$key] = $view;
        }
        else {
            $this->_views[] = $view;
        }
        return true;
    }    /**
     * Attach multiple views
     */
    public function attachViews(array $views)
    {
        foreach ($views as $key => $view) {
            $this->attachView($key, $view);
        }
    }
   
    /**
     * Get the attached views
     */
    public function getViews()
    {
        return $this->_views;
    }
    
    /**
     * Build the layout(s)
     */
    public function build()
    {
        foreach ($this->_views as $_view) {
            // create a predefined layout with the attached views (customizable)
            $_view->addViews(array(
                new View\PartialView('header.php'),
                new View\PartialView('body.php'),
                new View\PartialView('footer.php')
            ));
        }
    }
}

As you can see, the only responsibility of my layout builder was to store view objects in a protected $_views array, which in turn would be used by its “build()” method for creating a predefined layout with a set of templates (in this case, the class used the ones that you saw before, but it could be anything else).  

At this point, I was pretty happy with this simple builder, so I decided to try out its functionality with the following script:

<?phpuse App\Utility\LayoutBuilder as LayoutBuilder,
    App\View\CompositeView as CompositeView,
    App\View\PartialView as PartialView;// include the autoloader
require_once 'Autoloader.php';
Autoloader::getInstance();// create an instance of the layout builder
$layoutBuilder = new LayoutBuilder;// add some views to the layout builder
$layoutBuilder->attachViews(array(
    new PartialView,
    new CompositeView
));// generate the layouts with the attached views
$layoutBuilder->build();

So far, all was going fine. However, that joyful feeling went suddenly away, as soon as I ran the above script. Surprisingly, instead of seeing a pleasant message in my debugger, I was confronted with the following exception:

Fatal error: Uncaught exception 'InvalidArgumentException' with message 'A partial view cannot aggregate other views.' in /path/to/App.

What went wrong? After researching for a while, I realized that the following line was the troubling one:

// add some views to the layout builder
$layoutBuilder->attachViews(array(
    new PartialView,
    new CompositeView
));

Effectively (and unintentionally), the layout builder was passed a partial view object, which naturally was unable to add another view at runtime. But hold on a second! If the signature of the builder’s “attachView()” method accepts any type of view (be it a composite or a partial) it means that it should be amended to take only composites, or in the worst case, do the proper checking in the implementation.

Unfortunately, that’s nothing but infringing the “Open/Close” principle (http://en.wikipedia.org/wiki/Open/closed_principle). If client code (in this case my trivial layout builder) consumes instances of the base “AbstractView” class without expecting to receive a single exception, and it suddenly gets one from a derivative (a partial view), this is a clear sign that the latter doesn’t conform to the behavior of its parent. Yes, this is exactly what the Liskov Substitution Principle is aimed at avoiding!

In this particular situation the behavior of a partial view is indeed pretty logical (after all it’s a leaf in a composite implementation); the main issue here is that from the very beginning my nice and sweet composite view layer was seated upon a wrong abstraction. Put in a different way: why should I derivate a partial view from a composite parent, if it won’t have at least the same base behavior? Pretty pointless and problematic, indeed.

The bright side of this story is that I was finally able to define an appropriate hierarchy of composite view classes without violating the LSP, and also got the layout builder to consume only the type of objects that it really needed. Obviously, the solution required to do some refactoring and even define a few additional interfaces, but in the end my client (and myself) were happy with the results.

Of course, if you’re anything like me, at this moment you’ll be wondering what’s the driving logic that stands behind this solution, right? Fear not, as in the final installment of this tutorial I’ll be showing you the highly-improved, refactored version of my composite view rendering layer.

Closing Thoughts

In this first part of this tutorial, I provided you with an introduction to what the Liskov Substitution Principle is, its fundamentals and how its infringement can cause more headaches than one might think. As with other principles of Object Oriented Design, the application of LSP is something that requires a careful balance between the theory behind it and the pragmatism of most programming languages (and of reality itself). But, you should always keep it in mind when designing your own hierarchies of classes.

With that being said, make sure to stop by the final tutorial, as you’ll see how I managed to implement a LSP-compliant solution for my composite view module.

Don’t miss the last part! 



 
 
>>> More PHP Articles          >>> More By Alejandro Gervasio
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: