How and why use MVC in PHP?

Asked

Viewed 4,351 times

20

I always made websites and systems without problem using structured PHP, came the curiosity if it is possible to make a system in OOP completely and if it is more advantageous. Searching I found the MVC, but I’m having difficulties in understanding and using the same, all tutorials I found use Composer, but I have no need to use it, because I do not use frameworks, libraries, always do in pure PHP.

The question is clear in the title, first, why use it? Since for registration, editing and deleting systems the structured PHP works very well, at first I thought that MVC would only serve to complicate the code, in exchange let it more organized.

Another thing is that I’m not being able to understand, especially the View layer, could you give an example, Customer crud or something? Just to see if I understand.

  • 9

    MVC in PHP is for the guy to think he’s doing the right thing because he heard it in college, or in the X book he bought I don’t know where. Someone saw this in another language, and thought that in PHP it would work the same, but that not all languages work the same way. Meanwhile, the people who understand PHP do normal scripts in a good way, and the thing comes out faster and gives less maintenance. Academicism in scripting language only makes sense if there really is a need. 80% to 90% of the codes I see with MVC and OOP in PHP are horror shows. The other 10 to 20% are not for qq a.

  • 5
  • 5

    PS: I voted for the question because it is a valid doubt. My first comment is a protest against the modinhas, and not against the question. Which, by the way, I think should be done by every programmer who invents to adopt some practice.

  • I only cited frameworks because of the use of Composer in most of the MVC tutorials I’ve seen. I completely agree with @Bacco (except about OOP, which in PHP is good for creating libraries, otherwise it was a waste of time for language developers)For me, it’s better to have a well-structured, organized code than to follow a 'rule' that gives you more work. From what I understand, then it’s kind of a waste of time. Thanks for the comments, I will wait for answers, but only for the comments I’ve made the decision not to use MCV in PHP.

  • 3

    @Bacco, you’re absolutely right. My teacher inserted this concept in php for us, at first it seemed something "stylish", cool, but then I realized that I had no advantage, at least for small and academic jobs. It is an academic fad to insert a concept anyway without delving into it.

4 answers

19


introducing

MVC is the acronym for Model View Controller, an architecture standard used as a general structuring form of code that generates a user interface (html/css/js in the case of php). The central idea is to separate its application into three logical components:

  • model. Here’s the part of the application that deals with your entity’s logic, the codes you know how they work (the "problem domain" or the system’s "business rules" if you like buzzwords) and who know how to apply validations, conversions and interact with the database or persistence layer.

  • view. This layer is responsible for displaying the graphical interface and user interaction. Each "view" is a visual representation of its "model", so if we have a "Modelquestao" the "Viewquestao" is the one that knows how to display the model.

  • controller. The controller is responsible for receiving user data and deciding what to do with it. It will process requests, transform data from them (which comes in GET’s and POST’s in the case of web) and send everything to the appropriate model.

why use?

The main advantage is the clear separation of responsibilities that you have between the layers, each of them is responsible for a part of the work that your application does, this type of division is something essential if you want to work large amounts of code or as a team. A "sticky" application where you have a file/class that does everything (processes requests, handles entity data structures, displays content, etc.) can work well and do everything you need, but it’s a sacrifice to maintain, especially if you weren’t the guy who created her (and 6 months without looking at the code you wrote will make you think you were someone else).

The fact that this pattern is widely diffused is also a bonus, it is much easier you dive into other people’s code that uses an architectural model with which you are already familiar than in one that was structured according to the author’s taste.

how to use?

It is interesting that you are talking about how you wanted to make a system completely with OOP and it ended in MVC because you do not need to implement MVC using object orientation, the standard is at a higher abstraction level than the OO || functional || structured programming. It is true that almost always you will find references to MVC using OO, however this is because OO is ubiquitous nowadays.

To give you an example of MVC in code: suppose you decided for some reason that it is a good idea to make a stackoverflow competing application, and then thinking about the problem decided to start it by the entity "Question", your model could be the following:

namespace Model\Questao;

function build($id, $titulo, $ultimaEdicao, $gratificacao, $criadorId)) {
    // validamos nosso modelo
    validate($id, $titulo, $ultimaEdicao, $gratificacao, $criador);

    return [
        'id' => $id,
        'titulo' => $id,
        'ultimaEdicao' => $ultimaEdicao,
        'gratificacao' => $gratificacao,
        'criador' => $criadorId
    ];
}

function validate($id, $titulo, $ultimaEdicao, $gratificacao, $criadorId) {
    if (!is_int($id) || $id < 0) {
        throw new Exception('Id inválida');
    }
    else if (mb_strlen($titulo) < 5) {
        throw new Exception('Títulos de questões devem ter no minímo 5 caracters.');
    }
    else if ($ultimaEdicao && !ehUmaDatetimeValida($ultimaEdicao)) {
        throw new Exception('Data de última edição inválida');
    }
    else if ($gratificacao && $gratificacao < 50 || $gratificacao > 200) {
        throw new Exception('Gratificações devem ser entre 50 e 200 pontos.');
    }
    else if (!is_int($criadorId) || $criadorId <= 0) {
        throw new Exception('Usuário inválido.');
    }
}

function create($questao) {
    $sql = 'INSERT INTO question (title, creationDate, fk_id_user)';
    getDb()->query(
        $sql, [$questao['titulo'], date("Y-m-d H:i:s"), $questao['criador']]
    );

    // checar se a query deu certo, talvez carregar a id no objeto para uso, etc
}

function update ($questao) {
    // mesma coisa do create, mas dessa vez UPDATE ... WHERE id=$questao['id']
}

function recuperarTodas() {
    // faz um select na db e retorna um array de questões ( build(dados..) )
}

function recuperarPorId($id) {
    // faz um select na db e constrói a questão a ser retornada com "build"
}

// delete, getQuestaoByName, etc

Note how the question model knows the rules for building and validating an issue, as well as how to persist, update, delete and recover issues from the database. Now to the View:

namespace View\Questao;

use Model\Questao as M;

function exibirTodasAsQuestoes() {
    echo '<table>';
    echo '<thead><tr>Id</tr><tr>Titulo</tr><tr>Última edição</tr><tr>Gratificação</tr><tr>Criador</tr></thead>';
    echo '<tbody>';
    foreach(M\recuperarTodas() as $questao) {
        echo '<tr><td>' . $questão['id'] . '</td><td>' . $questão['titulo'] . '</td>' . 
            '<td>' . $questão['ultimaEdicao'] . '</td><td>' . $questão['gratificacao'] . '</td>' . 
            '<td>' . $questão['criador'] . '</td></tr>';
    } 
    echo '</tbody></table>':
}

function exibirQuestao($questao) {
    // sabe como exibir o html correto para uma questão específica
}

function exibirErro($error) {
    echo // exibe o erro apropriadamente formatado
}

// etc

The view knows how to display the question in different contexts (listing, display, etc) and communicates with the model who knows the internal structure of "Question" and knows how to recover the data from the persistence layer. Finally the controller:

namespace Controller\Questao;

use Model\Questao as M;
use View\Questao as V;

function post() {

    // também faz Sanitização do conteúdo, checa se não possui conteúdo malicioso, etc
    // todo o processamento que não é específico deste modelo.
    $id = $_POST['id'];
    $titulo = $_POST['titulo'];
    $ultimaEdicao = $_POST['ultimaEdicao'];
    $gratificacao = $_POST['gratificacao'];
    $criadorId = $_POST['criador'];

    try { 
        $questao = M\build($id, $titulo, $ultimaEdicao, $gratificacao, $criadorId);
        if ($questao['id']) { // possui id, atualizar
            M\update($questao);
        }
        else { // sem ID, criar
            M\create($questao);
        }
    }
    catch(Exception e) {
        V\exibirErro($e->getMessage());
    }
}

function exibir() {
    $id = $_POST['id'];
    $questao = M\recuperarPorId($id);
    V\exibirQUestao($questao);
}

// etc

The controller receives user requests, performs general processing on the data of this request, calls the right functions in the model and displays data by view if necessary.

Note how I didn’t use classes, just namespaces (because after all working with global is right headache) and functions, but you could easily carry this model to an OO or even remove the namespaces if you wish, the important thing is to understand that one can implement MVC in any desired paradigm.

Obs: the code may contain some errors, do not take it to the letter as it is just an example.

should I wear?

How big is your application? Who will develop it? Is it just you? Who will maintain it? depends on many factors, whether you are doing a project that you will throw away after (kind of a college job) or something really very simple maybe it is overengineering. However if you plan to make a great application and will need to maintain for a long period of time worth considering this pattern, remembering of course that there are other alternatives and MVC is only one of them.

  • 3

    Good example and +1 for highlighting that MVC does not depend on OO or other paradigm.

  • @rray I was going to say the same thing, including I know a framework (well ruinzinho by the way) that has a good part being structural. I liked the part that quoted "if you are doing a project you will throw away after" :)

  • @Guilhermenascimento o CI? xD do not know how is the v3 but the previous ones ...

  • @rray is kissmvc, the "controllers" (or better the actions) are functions, without classes, although it has abstraction of a controller class, but it is very buggy and "strange", I only used once to play, maybe I’m wrong :)

  • @rray hehehe Until CI3 is cool, I tested a few days ago

5

How and why to use MVC in PHP?

The best link I can give you that will open your mind is this http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html The Portuguese translation can be found here: http://andreiabohner.org/symfony2docs/book/from_flat_php_to_symfony2.html

But what is MVC?

MVC is just a design standard. There are several different standards suggested by books, articles, tech companies and developers of great prestige.

You, as a software developer, programmer or architect are not required to use any design standards offered by others. You, how to be thinking, can create your own design pattern.

After all, what is design standard?

A project pattern is just how to define how your code should be organized and how it should behave.

When ONE or more developers decide to create a project, split efforts and join the parts that each one has made, it is ideal to define a project pattern. So in the future, when codes need to be integrated to form the application, it’s easier to understand what each developer has done.

Also, in the future, when you need to go back in old code to fix a bug, if your code follows a project pattern, it’s easier for you to read and remember what the code should do.

Read this wikipedia article: https://en.wikipedia.org/wiki/Software_design_pattern

I also recommend that you buy, and study, a good software architecture book. A very good one is Roger Pressman’s "Software Engineering: A Professional Approach".

2

OOP and MVC are two separate things. MVC is a design standard where it basically separates the layers of responsibilities where M represents the business logic, C represents the controller and V represents the interface. It is possible, without any problem, to structure codes in the MVC standard without using object orientation. The creator of PHP himself, Rasmus Lerdorf, 10 years ago, wrote an article from which he was misinterpreted so he rewrote another article available on the link: https://toys.lerdorf.com/archives/38-The-no-framework-PHP-MVC-framework.html

The criticisms he received were actually from haters who disliked what he commented in the original article. In the original article he literally chopped wood (made severe criticism) to the "irrational" use of OOP in PHP. Then he saw, he received a storm of haters who did not understand what he meant, as if he was saying that OOP was something useless and unnecessary.

Finally, when you think about MVC, don’t think about OOP. MVC isn’t even an object. It is merely a design standard for organizing codes and routines.

Most likely you already use some MVC unintentionally. Maybe with one violation or another, but anyway you already do it. For example, if you write PHP codes without mixing with CSS, HTML, JS, among others, you are already making a good separation between the view and the controllers. The most confusing point is knowing how to separate what the controller is and what the model is.

Part of the question you asked emphasizes the OOP, however, as this is not the focus in question, I will restrict the answer to the MVC.

The existing answers already say enough, therefore, not to repeat the obvious, we go directly to a practical and simple example, without use of classes. Something that any early PHP programmer who knows at least how to use variables and functions, can understand.

<?php
/*
Bootstrap
*/
date_default_timezone_set('Asia/Tokyo');
ini_set('error_reporting', E_ALL);
ini_set('log_errors', true);
ini_set('html_errors', false);
ini_set('display_errors', true);
define('CHARSET', 'UTF-8');
ini_set('default_charset', CHARSET);
mb_http_output(CHARSET);
mb_internal_encoding(CHARSET);

/*
Controller
*/
function Control()
{
    $m = null;
    if (isset($_REQUEST['m'])) {
        $m = trim($_REQUEST['m']);
    }
    if (empty($m)) {
        $m = 'Foo';
    }

    /* 
    Call the model
    */
    $f = 'Model'.$m;
    $data = $f();

    /* 
    Call the view
    */
    $f = 'View'.$m;
    $f($data);
}

/*
Foo Model
*/
function ModelFoo()
{
    return array(
        'body' => array('a', 'b', 'c'),
        'header_charset' => CHARSET,
        'header_content_type' => 'text/html'
    );
}

/*
Foo View
*/
function ViewFoo($data)
{
    header('Content-Type: '.$data['header_content_type'].'; charset='.$data['header_charset']);
    echo '<html>
    <body>
        Foo Page<br />'.
        $data['body'][0].$data['body'][1].$data['body'][2].'
    </body>
    </html>';
}

/*
Bar Model
*/
function ModelBar()
{
    return array(
        'body' => array('a', 'b', 'c'),
        'header_charset' => CHARSET,
        'header_content_type' => 'text/html'
    );
}

/*
Bar View
*/
function ViewBar($data)
{
    header('Content-Type: '.$data['header_content_type'].'; charset='.$data['header_charset']);
    echo '<html>
    <body>
        Bar Page<br />'.
        $data['body'][0].$data['body'][1].$data['body'][2].'
    </body>
    </html>';
}

/*
Start the engine
*/
Control();

/*
Para executar, acesse pelo browser 
http://localhost/mvc/?m=Bar 
ou http://localhost/mvc/ 
e veja o resultado desse mini framework.
*/

In the example I did no validation to avoid filling with too many codes and demonstrating the MVC layers more clearly. Therefore, be aware that you need to create consistent and secure code. The above example is merely illustrative.

In this application we have 2 models and each model has 1 view, so 2 models and 2 views.

There is a single controller, which decides what to do with the input from the user. GET/POST requests. In the above example I simplified with $_REQUEST.

A very common problem to find is the misuse of the pattern where apply parts of the business model within the controller or parts of the view within the model or even the controller.

Examples of very common errors

Violating the controller

function anti_injection_sql($str){
    // Suponha que aqui tenha uma rotina para tratar injeções sql, das mais bizarras e sem sentido. 
    return $str;
}

function Control()
{
    $m = null;
    if (isset($_REQUEST['m'])) {
        $m = trim($_REQUEST['m']);
    }

    /*
    Por quê fazer filtragem contra sql injection aqui? 
    Não é responsabilidade do Controller, a menos que esse parâmetro seja usado pelo controller para buscar no banco de dados algo específico somente do controller.
    Mas enfim, normalmente é desnecessário. Está apenas violando o MVC e corrompendo a entrada original.

    Como aqui não há nenhuma consulta a banco de dados, não faz sentido.
    */
    $m = anti_injection_sql($m);

    if (empty($m)) {
        $m = 'Foo';
    }

Violating the model

function ModelFoo()
{
    /*
    Observe o código HTML `<b></b>` dentro do array que será enviado para a view. Ainda estamos no Model, não deveria ter nada de HTML formatando o conteúdo da view aqui.
    */
    return array(
        'body' => array('<b>a</b>', 'b', 'c'),
        'header_charset' => CHARSET,
        'header_content_type' => 'text/html'
    );
}

Violating the view

/*
Bootstrap
*/
date_default_timezone_set('Asia/Tokyo');
ini_set('error_reporting', E_ALL);

/*
Aqui dispara um cabeçalho que informa o tipo do conteúdo e conjunto de caracteres.
Isso torna a aplicação inteira "engessada" pois se precisar exibir uma view com um content-type ou charset diferente?
E se precisar usar funções como session_start() que conflitarão com cabeçalhos previamente despachados?
Nesses casos, com certeza vai acabar resolvendo com mais gambiarras e, é o que acontece normalmente.
O cabeçalho faz parte da view, portanto, é responsabilidade dessa camada.
*/
header('Content-Type: text/html; charset=UTF-8);

The view is dumb?

Here we also have a little confusion, because in the example we mixed PHP with HTML in the view and at the same time stated that in MVC should not mix PHP with HTML.

The fact is, the view needs to be compiled somehow. Here, as we deal with PHP, we use PHP itself to compile. In order to make the example as simple as possible, I avoided using a complex example with a template compiler as it would make the example too complex. Basically, the view can’t be "dumb". After all, HTML is not a programming language where we can use flow control structure, loops, among others.

Alternatively we can use Javascript to control the layout of the data in the view, so the view templates would be 100% free of PHP code.

For this there are tools like jquery template, mustache, handlebars, among others.

As not everything are flowers we find a flaw, because to build a website we need to worry about SEO (search engines). Search engines do not compile Javascript making it a problem to use Javascript as a template engine. But at that point we enter into another discussion that is not the case discuss here.

In short, don’t take "don’t mix php with html" literally. This should be interpreted as "don’t mix the MVC layers".

function ViewFoo($data)
{
    header('Content-Type: '.$data['header_content_type'].'; charset='.$data['header_charset']);
    echo '<html>
    <body>
        Foo Page<br />'.
        $data['body'][0].$data['body'][1].$data['body'][2].'
    </body>
    </html>';
}

Eventually there will be situations where it will be necessary to invoke routines within the view. It would be a violation to write routines in the view and so something was created that we know as "helpers". It’s an elegant way to rape, to sniff around the view in an acceptable way.

Helpers make it easy to mount views, such as HTML headers, mounting menus, links, etc.

Performance

You must have noticed the parameter passages in the controller:

/* 
Call the model
*/
$f = 'Model'.$m;
$data = $f();

/* 
Call the view
*/
$f = 'View'.$m;
$f($data);

In procedural-style programming, we wouldn’t do so many loops and save processes, memory, etc. So why should I give up the performance of simpler code to write more complex code that will consume more memory and processes?

The whole thing about the OOP concept is to intelligently reuse routines. In fact, you start writing less code. It focuses more on business logic (Model) than on control processes. In procedural programming, we practically reinvent the wheel for each new business logic. These are repetitive processes that, when you don’t have an organization, turn maintenance into a nightmare.

In the code snippet above, for example, we could eliminate the use of a new variable $data = $f(); trading it for a class property. Thus avoiding transporting the same data in different objects.

When to use? Should I use? Where would OOP enter?

As you can see, in this ridiculous little framework we find a lot of things that need implementations making it quite complex. Imagine in an average system, how big is the complexity of writing organized and consistent code?

In structural programming, the amount of codes and concepts become unviable for maintenance even in small systems. That is why there is OOP and its various concepts and paradigms. The decision to use an X or Y concept depends on the programmer. There is no law that says how we should write the codes. What exists are recommendations of what to do and what to apply in a situation A or B.

Obviously, let’s not overreact. If you need to create a 1-page HTML site with a 3-field contact form, it’s obvious you won’t need to use OOP. A simple $_POST, isset(), if else and mail() already resolves.

0

What’s the MVC for?

To try to put the programmer inside a box called "STANDARD". It gives chills to hear this word. Ew!

I used MVC only one day, I thought it was cool, well thought out. But... It’s not for me!

At first I used Drupal, it was cool, but then I thought about all these classes and functions that I won’t use?

There’s no logic to it! I tried the Wordpress and the same question. I went from PHP pure indeed. I have developed only what I will use, and every now and then I change the classes and functions so that they become more compact and do the same thing. A different idea always appears, a different, better and faster way to do the same thing. That’s awesome! One CMS does not allow it. There is no right way to do anything, there is your way of doing things.

What method allows you to let go?

Which allows you the freedom to do without limitations. When you learn to program without a teacher, you don’t even make a flow diagram in your fingernail. Some of us don’t even have the habit of formatting the code (me).

Use a text editor on Linux, super basic called Medit, not made for programming, but leaves any color programming code according to the language. I love it!

Seems old-fashioned!?

Some would say that a IDE would be more practical. But it would not be better to type each function that will be used?

Each one has his opinion and every opinion must be respected because it is taken from one point of view. But the right answer is: There is no 'has to'. Pattern is something coined so people don’t dare too much. It’s like BLINKERS who put themselves on the horses so that they don’t look the other way and just do what is expected of them - to be guided by the driver - without seeing anything around them other than the path in front of them. That’s sad, but that’s right. Try and make your decision, because what can be good for one is actually bad or fatal for others!

  • 1

    Today, almost a year after the question, and already knowing much more about the subject and others, I see that the MVC is something essential, but not only the MVC, but any other development pattern, in the organization of the code nor speak, when it is associated with a framework then the time gain is infinitely greater. On FDI, I agree. On the answer, it slipped a bit from the central context of the question.

  • I think the user confused CMS with MVC.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.