tags:

views:

888

answers:

4

Lets say I have a class called PageBuilder which I instantiate, send parameters to and call functions from through my index file (which acts as a front controller). There are three sub classes associated with the PageBuilder class: Head, Body and Foot, that are accessed by PageBuilder which basically abstracts them for index.

So in theory you could instantiate PageBuilder and have full access to the other classes as if they were part of PageBuilder.

How can I implement a design like this in PHP5 using any combination of classes, abstract classes and interfaces?

I don't think the above is possible with PHP5, not necessarily because PHP has its limitations but maybe because I am going about the design of my application the wrong way.

Common examples of OOP in PHP don't suffice to help me understand how to structure a more complex design.

Thanks.

A: 

PHP only allows you to extend one parent class (which can in turn extend another parent class, etc.). There are no interfaces, meaning you can't inherit functions or properties from multiple interfaces as you could in C++.

As such, you will probably need to do something more like this:

class PageBuilder {
    protected Head, Body, Foot;

    public function __construct($request) {
        $view = $this->getView($request);

        $this->Head = new PageSection('head.tpl');
        $this->Body = new PageSection($view);
        $this->Foot = new PageSection('foot.tpl');
    }

    private function getView($request) {
        // @todo return the template filename/path based upon the request URL
    }
}

class PageSection {
    private $template;

    public function __construct($template) {
        $this->template = $template;
    }

    public function render() {
        // @todo process and output the $this->template file
    }
}
Matt Huggins
PHP has interfaces, and you can implement multiple of them. I believe you are confusing interfaces and abstract classes, and implementing versus extending.
notJim
I thought PHP5 did have interfaces: http://php.net/manual/en/language.oop5.interfaces.phpAlso in you example above how would I send many function parameters from PageBuilder to PageSection. For example I could have various parameters to be set (that I would set through index.php) such as the title or meta tag information?
Allen
Well damn, what do you know. I'm embarrassed and enlightened.
Matt Huggins
Lol I have never actually used an interface in PHP anyway.
Allen
+2  A: 

From what I understand here you could use the composite pattern

http://en.wikipedia.org/wiki/Composite_pattern

Your controller index has only access to an object that implements an interface IPageBuilder (or a name similar), with some standards function like "generatePage". This object would in reality be some kind of container that contain other object of type IPageBuilder. Those leafs object would be able to build some subsection of the page, like Head, Body and Foot. Each of those leaf object would be of a different class, but they will implement the IPageBuilder interface. When your index object call "generatePage", the container will call in order the "generatePage" method of each of its leaf objects, that will in turn take care of rendering the HTML.

Using this approach, if your Body class become too big, you can always turn it into a container that implements the IPageBuilder interface, for example a blog post Body could consist of an Article object and a CommentList object. The body object would then only propagate the "generatePage" method to its children object.

To create your IPageBuilder object, you can use a factory patterns

http://en.wikipedia.org/wiki/Factory_method_pattern

In all honesty, I have tried those kind of approach in the past to generate my HTML and found them to be kind of overkill. My suggestion would be to use a templating engine instead, like Smarty. Your designer will love you (or hate you less) if do that ^^.

http://www.smarty.net/

If you want to know how to use interfaces in PHP, not that it's very hard...

http://ca.php.net/manual/en/language.oop5.interfaces.php

Laurent Bourgault-Roy
A: 

So if I understand correctly you want Head, Body, and Foot to automatically construct as children of PageBuilder?

There are a couple of ways you could maybe do this.

1) Create variables inside of PageBuilder to hold the classes and use a __call method

class PageBuilder{
   private _head;
   private _body;
   private _foot;

   function __construct(){
       $this->_head = new Head();
       $this->_foot = new Foot();
       $this->_body = new Body();
   }

   function __call($name, $args){
       if(method_exists($this->_head, $name)) call_user_func_array(array($this->head, $name), $args);

       // Repeat for other classes.

   }

}

The problem here obviously being if two classes share the same method then the first one to come up wins. You could probably modify it to pick a class based on the function name pretty easily.

2) Chain everything down.

Abstract class Page{
}

class Head extends Page{
}

class Body extends Head{
}

class Foot extends Body{
}

class PageBuilder extends Foot{
}

Either way its somewhat hacked, you just kind of have to make it work.

Brent Kirby
+1  A: 

Some of the other answers are on the right track. The problem you're running into is that your PageBuilder class is doing too much. Just the name sounds wrong for what you're trying to do with it. A PageBuilder sounds like something that would assemble a bunch of parts together into a Page. Let's call these parts Section. Then, what you want to do is use composition, as several of the answers have hinted at.

Inheritance is often described as an is-a relationship, as in if your Section classes extend the PageBuilder class, then a Section is a PageBuilder. What you want though is a has-a relation ship, as in your PageBuilder class has a (or many) Section(s). Any time you need a has-a relationship, you should be looking toward composition rather than inheritance.

So here might be your class hierarchy:

abstract class PageBuilder
{
    //@var Section
    public $header;

    //@var Section
    public $body;

    //@var Section
    public $footer;

    public function render()
    {
        echo $this->header.$this->body.$this->footer;
    }
}

class Section
{
    protected $content;
}

class LoginPage
    extends PageBuilder
{
    public function __construct()
    {
        $this->header=new Section(...);
        $this->footer=new Section(...);
        $this->body=new Section(...);
    }
}

At this point, you're really kind of re-inventing the wheel by making a crappy MVC system. If this is for a project (rather than for learning), you should consider using one of the MVC frameworks for PHP. (I recommend Kohana, but there are several questions regarding the best PHP versions on Stack Overflow.) If you're thinking of these kinds of things, MVC probably won't be a great leap for you.

notJim
This is really great information. It is really awesome that you could tell I was thinking MVC because I have been trying to build my own simple MVC framework for a while. I finally just give up and started working on a mini general design framework which is what this question is based upon.Funny how things work out...I am making my own framework for the following reasons: 1)Learning 2)To be part of a super simple site I am building that doesn't merit me learning a big framework, but by doing this mini framework I can scratch my overkill itch. Don't try to convince me otherwise ;-).
Allen
Just to add: Is there any place to find decent tutorials on building PHP OOP frameworks? All of the obvious ones I have found through Google and in books have been amateurish, brief or have some sort of major flaw in the design or description. I feel like i'm flying blind! The only suggestions I ever get refer to some sort of (relatively) large framework such as CakePHP, Kohana, Zend MVC, ect...
Allen
notJim
If you're going to go down the road of inundating yourself with the literal multitude of PHP frameworks because you absolutely must learn this stuff and make web software, I recommend that you look at http://www.pradosoft.com/ Of the myriad frameworks I've played with, it seems like one of the most innovative.
RibaldEddie
@allen: if my answer answered your question, please accept it as the answer by clicking the green checkmark. If not, feel free to followup more. :)
notJim
I was thinking of giving you the answer, but I am going to wait till morning before I cut it off officially.
Allen
Okay, no worries.
notJim