mvc example: form post
Object Oriented Programming Improvements

The first thing you can do to improve code like this is to use dependency injection, instead of instantiating objects with new inside of objects.

// Setup your class hierarchies like this.

abstract class Controller
{
    protected $model;

    protected function __construct(Model $model)
    {
        $this-&gt;model = $model;
    }
}

class RootController extends Controller // or HomeController extends Controller
{
    public function __construct(Model $model)
    {
        parent::__construct($model);
    }
}


Then you execute:

$controller = new RootController(new RootModel());  // But, read on.


Notice the use of type hinting in the __construct function. Program to an interface, not an implementation. 

Use abstract classes (which you cannot make an instance of) to factor out common properties and methods into one place. Extend abstract classes with specific species of classes. This is where the power of polymorphism via the Strategy Pattern comes in to play!

By type hinting with abstract classes, or interface types, you will not have to change your code simply because a different species of child object need to be used at some other point in time.

If you find that the parents of several classes should have the same functionality or constants, factor again and define a PHP Interface and slap it on to a class like this.

class RootController extends Controller implements Printable
{
    public function __construct(Model $model)
    {
        parent::_construct($model);
    }
}


Where in this case, Printable would be a set of virtual functions, and or constants, that form a contract, forcing any class that implements Printable to define certain public functions / hooks so that it can be used as a "Printable" object by unrelated code in other places.

Model-View-Controller Improvements

In terms of MVC, you may want to consider how a Model is going to send data to a View. Using a Controller's method as the working area for passing dat from a Model to a View is common. If a Controller's method can act as a working space for a particular command, then "M" and "V" (Model and View) can use "C's" method as a place to coordinate things.

Given the following, you could use your programming knowledge to devise a solution where a View is passed data from a Model, without injecting an instance of said Model into a View. In other words, you do not want to do this.

abstract class View
{
    protected $model;

    protected function __construct(Model $model)
    {
        $this-&gt;model = $model;
    }
}

class NewsletterView extends View
{
    public function __construct(Model $model)
    {
        parent::__constrcut($model);
    }
}


Summarizing, there are two well known options:


Use a method of a Controller (i.e. a command). Have the Model pass a data structure (array or iterable object) to the View.
Give the View a reference to the Model and delegate the chore of getting data to the Model within the View. However, as noted this is not what you want to do.


Note that option #2 can create strong coupling between a Model and a View, because the View must then use methods off of the Model instance to get at data. If a Model's methods change (such as the names, or method parameters), the View will have to change, accordingly.

What you want to do is have a setup like this.

abstract class Controller
{
    protected $model;
    protected $view;

    protected function __construct(Model $model, View $view)
    {
        $this-&gt;model = $model;
        $this-&gt;view = $view;
    }
}

class NewsletterController extends Controller // or HomeController extends Controller
{
    public function __construct(Model $model, View $view)
    {
        parent::__construct($model, $view);
    }

    /**
    * A totally made up method.
    */
    public function register(array $suscriberData) 
    {
        $viewData = $this-&gt;model-&gt;addSubscriber($suscriberData));
        $this-&gt;view=&gt;updateRegistrationPage($viewData);
    }
}


Then you execute:

$controller = new NewsletterController(new NewsletterModel(), new NewsletterView());


(Note: A dependency injection container can resolve class dependencies off screen and just issue you the object you request! Very handy, but not mandatory.)

Your URL to such a command would be:

http://yourdomain.com/newsletter/register

Where "newsletter" is your Controller, and "register" is the command.

Typically, the machinery of a framework (Front Controller / Router / Dispatcher), or just good programming generally, handles transforming the path component of a URL (REQUEST_URI) into an instance of a Controller. In that case, because instances are being created dynamically, you will want to use a class autoloader (as in PHP-FIG PSR-4) at minimum. Using an autoloader can eliminate all but one require statement for accessing classes. You will need one require statement to bring your autoloader code into scope. :-)

This is why people are encouraged to use namespaces with their OO PHP code. Using a PSR-4 compliant autoloader will automatically find and load your custom classes! The implication being, that your include_path no longer needs to list every dog-on path that you have classes loading from! ;-)

However, if you use modular HTML templates for your web pages (require header.php, require footer.php, require aside.php, etc ..), be sure to have the location of those files in your include_path!

Dependency injection containers are not mandatory, but they do simplify the usage of objects by decoupling where a class is instantiated from where it is used. In other words, a DI container is a very precise gumball machine for objects and other data. :-)