Theory
In a macro design level the MVC is a architectural decision that states that there are three concepts in development that must be separated. Model, View and Controller.
To avoid more "MVC theory" duplication over SO, this is a very accepted answer where it is explained the basics of MVC: https://stackoverflow.com/a/5864000/1311025
Implementations of MVC
You have to choose the implementation that is right for your project requirements and perspectives of changes.
For example. If I develop thinking that my database will change in the future (I don't know when, I just suspect it will change) I'll make an implementation that decouples absolutely my database, creating a layer that abstracts the implementation of it from the controller. and implement a factory that provides you the right instance to access the database.
If I think my view will change, then I'll use an observer pattern in the view to decouple both controller and view. And with events the controller and the view will communicate.
You can then, construct your own implementation of MVC following software design patterns that fulfill your needs.
Now, from the code you provided,
<?php
$model = new Model();
$controller = new Controller($model);
$view = new View($controller, $model);
if (isset($_GET['action']) && !empty($_GET['action'])) {
$controller->{$_GET['action']}();
}
echo $view->output();
thought is separating the responsibilities in classes (Model, View and Controller), for me, this is an example of coupling the view with the model. But It could be right if we want that the view, the controller and the model will be forever like this and will never change.
Also with this implementation the controller has an state, which reflects that this will never scales (or not in an easy way).
Disclaimer: This is my implementation for an easy, quick and little project.
If you need a more serious solution, where quality is not an option,
then you must follow more strict guidelines.
In my opinion, I'll choose to decouple at least the view from the model.
<?php
$controller = new Controller();
if (isset($_GET['action']) && !empty($_GET['action'])) {
$controller->doAction($_GET['action']);
}
The controller does not have to handle with global php variables ($_GET):
<?php
Controller {
public function __construct() {}
public function doAction($action) {
$model = new User();
$model->setName("user36279");
//This just transforms the user model in an associative array
$UserDTO = $model->toDTO();
$view = new UserView();
//We don't send the model to the view increasing decoupling
$view->render($UserDTO);
}
}
But this would be my implementation. Now is your choice to decide how much you want to decouple, how much maintainability, complexity, testability you want.
Edit:
Someone pointed that:
[...] your "controller" is actually responsible for routing, retrieval
of information from model layer and rendering of response, which of
course is violating both SRP and SoC. Bottom line: all of this is
completely wrong
He is right, my code is violating SRP. But check out this question:
Does the traditional use of the controller in MVC lead to a violation of the Single Responsibility Principle?
And if you want to follow the SRP, you disaggregate your Controller
into a Dispatcher and Actions; the Dispatcher dispatches control to
its actions [...]
Why don't we see this more often? Because Controllers are often "ad
hoc" implementations, leaf-level concrete classes that aren't
generalized and aren't meant to be subclassed. Here, the class is used
more to conveniently group code, the actions are almost certainly
non-public (likely private, maybe protected), "merely" internal
implementation details.
The choice of how to decide what action to dispatch to, the number and
diversity of possible actions, is high, and dispatching and action are
tightly-coupled. So in practice, it's often easier to just put the
code together in one place.
SOLID principles are a great guideline to design object oriented. The general rule here is to acknowledge the different alternatives and choose the one that best fit your needs. Principles are guidelines not rules and the major advantage of following the principles are a set of common solutions that are agnostic of languages, easy to use and understand for both novices and expert developers and simplicity in our design.
Bottom line: It's up to you when you need to apply SRP (Single Responsibility Principle) and consequently, SOLID.