Simple MVC example please scrutinize

here is a simple mvc Example it does not contain any mumbo jumbo.
this is pretty long so if your up for a good read carry on.
I have been rude in the past so if you fell like being rude back I don’t mind lol.
This does not contain any error checking, and is not scalable, just a simple opinionated example, which might be helpful to some or irritating to others.
Well here it goes.
all files located in same directory
this is a two file wonder
this is MVC.php


class Controller {
    protected $_model;
    protected $_view;

    public function __construct(View $view, $model = null){
        $this->_view = $view;
        if($model && $model instanceof Model){
            $this->_model = $model;
        }
    }

    public function setView(View $view){
        $this->_view = $view;
    }

    public function getView(){
        return $this->_view;
    }

    public function setModel(Model $model){
        $this->_model = $model;
    }

    public function getModel(){
        return $this->_model;
    }
    
    public function update(){
        if($this->_model){
            $this->_view = $this->_model->updateView($this->_view);
        }
    }
}

class View {
    protected $_viewVars;
    protected $_content;

    public function __construct(array $viewVars = array()){
        $this->_viewVars = $viewVars;
    }

    public function setViewVars(array $viewVars = array()){
        if($viewVars === array()){
            return;
        }
        $this->_viewVars = array_merge($viewVars, $this->_viewVars);
    }

    public function  __set($name, $value) {
        $this->_viewVars[$name] = $value;
    }

    public function __get($name){
        if(isset($this->_viewVars[$name])){
            return $this->_viewVars[$name];
        }
    }

    public function setContent($content) {
        if(is_file($content)){
            $this->_content = $content;
        }
    }

    public function render() {
        ob_start();
        if($this->_content){
            include $this->_content;
        }
        echo ob_get_clean();
    }
}

class Model {
    protected $_modelVars = array();

    public function setModelVars(array $vars = array()){
        $this->_modelVars = $vars;
    }

    public function getModelVars(){
        return $this->_modelVars;
    }

    public function updateView(View $view){
        if(!empty($this->_modelVars)){
            $view->setViewVars($this->_modelVars);
        }
        return $view;
    }
}
//testing simple concept

$view = new View(array('var1' => 'var1'));
$view->setContent('testView.php');

$model = new Model();
$model->setModelVars(array('modelVar' => 'modelVar'));

$controller = new Controller($view, $model);
// before view gets updated by the model
$controller->getView()->render();
$controller->update();
//after view gets updated by the model
$controller->getView()->render();

now here is testView.php


here is content with a variable: <?php echo $this->var1; ?> and here is the model update var: <?php echo $this->modelVar; ?> <br/>

This I find is simple while not elegant or too complicated. I am sure it can be simplified more, hopefully not to the point of function calls though. I thought I would throw it out in the wild in hopes of furthering everyones education about MVC concepts, hopefully with comments from other more experienced users of the SitePoint PHP Application Design forum.
I thank you for your time.

Seeing an implementation which avoids the controller acting as a gateway is always nice :slight_smile:

The only thing I would say is that the model shouldn’t really know of the view and instead the view should request data from the model.

While not a problem in your simple example, if you want to reuse the model with multiple views (and this is a desirable feature), your views must have the “setViewVars” method.

This ties your model to a specific interface which is something generally discouraged. The first problem you will run into will come in maintainability. By passing the vars from the model to the view, the view expects a certain data set. Now, you could, as you suggest, implement manual error checking… but if the view requested data from the model it would be unnecessary as the error would be automatically triggered by trying to read the model.

In desktop applications the model often has knowledge of the view in order for it to notify the view when it’s updated. On the web this is irrelevant since a model refresh or a view refresh requires a page reload and therefore both refresh anyway.

How are you handling controller actions?

General rules of thumb…

Models respond - they don’t initiate. They aren’t aware of the controller or view. Each of those might ask the models for data, but the model doesn’t know or care

Controllers instruct, they don’t respond. In many PHP frameworks they get information from models and pass it onto the views, but its more correct for them to get DATA models from the DOMAIN model and pass those models over to the view so that the view can ask those models specific to their needs.

Views take orders from the control and update the view state, but they don’t respond normally. If they throw an error the controller must catch the error, but this shouldn’t occur normally.

Desktop applications make more extensive use of the Observer pattern in order to avoid doing just that because it’s a potential sore point to have a model have any knowledge of the view. PHP applications that use extensive caching can run into a similar situation since they don’t necessarily refresh all objects when they wake up from cache. For this reason PHP does have an Observer interface.

In the Observer pattern the model would extend the Subject Interface. Anytime it changes it would fire it’s notify method and announce what changed. Any watching objects implementing the Observer Interface (most of them are likely to be views but they could be anything) will see this and can then act upon the change.

Using this pattern the model remains in the dark about what cares about changes to its state - views usually but for example the Domain Model would care if the Data Model of the User Object undergoes a change that alters its permissions.

I can’t go into that much more cause I’m still studying it and taking it in.

Getting back to the original post, TomB’s right - it is nice to see a controller idea that doesn’t have the controller acting as the gateway and router; that said those concerns do belong in the code area called the controller in my opinion. It’s just that a given controller shouldn’t be concerned with this stuff. There’s also a difference between controller code and a controller class. The gateway and page router are control concerns since they are part of the application’s program flow. Domain models and data access objects are all model concerns - template files and view classes that work with them are views. There is no “view” class, “model” class and “control” class that handles everything in that area of concern - its just too much work to expect of one class.

The other thing that jumps out to me is the leading _ on variable names and methods that are protected or private. This was common in PHP 4 but is no longer necessary and should be avoided because its bad practice (hungarian notation in general is bad). The reason its bad is what happens if you want to change the access level of a method or property - now to be consistent you have to go around and change its name everywhere it is referenced in the class which is bound to cause headaches (It’s also why Hungarian notation is a bad idea). And if you don’t revise then the _ suddenly becomes misleading or meaningless.

That isn’t true at all. Making the model dependent on the view completely negates a fundamental principle of the pattern. In most cases views react to events dispatched by the model leaving the model completely decoupled from the view. The model should never have knowledge of the view regardless of persistent or non-persistent environment. That is one of the most significant and concrete criteria governing the pattern.

I.E. The Observer pattern. Repeating myself here - In PHP a model that wants to use this pattern implements the Subject interface and whenever a state change occurs it fires it’s notify event. Anything that wants to be able to watch subjects implements the observer interface and uses the methods there to pick out what they want to observe and what they want to do when certain events occur. The way the interface works is dependencies between subject and observer do not have to be passed. The observer is aware of the subject, but not the other way around. Subjects, whatever they are, are decoupled from their observers

Note that models can be observers of other models without violating MVC pattern - and indeed this shouldn’t be that surprising if you think about it - though usually the domain model will be doing the observing.

I’m thinking Tom might have been thinking of how one would emulate the notify method without implementing the interfaces in question. In that case it’s tempting to say that the view registers itself with the model it wants to observe. However this is incorrect. In a language that doesn’t have a direct means of implementing the Observer/Subject pattern a dispatcher class should be written. Subjects notify the dispatcher and it relays to the correct observers what has occurred.

In the underlying PHP interpreter I believe this is what occurs - but it gets abstracted. Even if you wrote a dispatcher yourself that would still be a form of control code - not a view, so views are still kept decoupled from views in this approach.

I was trying to talk in broad terms. It has ‘knowledge of’ insofar as it knows it’s going to be represented by one or more views. Yes it usually uses the observer pattern. The point i was trying to make is that it’s not needed on the web and without going into implementation details of something that’s of little use to people reading the PHP forum.

I thought MVC was just a theory to create interfaces and Abstract classes that then can be utilized in any way, because if you use MVC in your frameworks name you will always get h8ers that say “oh no, that’s not right. It should be like this.”.
While theory does not equal practicality and theory is constantly updated, MVC is a sound theory based on design patterns. Some will always scrutinize it’s existence in the PHP community, because PHP was just made as a perl wrapper and while it has grown into one of the easiest languages to learn, some might say that it teaches bad programming concepts, but you can also say that PHP is the door that opens people to programming concepts.
Compiled languages can utilize MVC more efficiently, than dynamic languages and while PHP does have the extensions to make compiled programs, they are not included in a vanilla PHP installation.
This was just an example to help foster Discussion. I thank you for your time.:slight_smile: