MVC is an architectural pattern that separates an application into model, view, and controller.
So far, you’ve likely written “Spaghetti Code”: files where you mix database connection, business logic (if/else), and the final HTML, all jumbled together in the same .php file.
The MVC pattern comes to bring order. It proposes separating your code into three distinct layers, each with a single responsibility.
The Three Musketeers
It is responsible for managing information and business logic.
- Talks to the database (SQL).
- Validates rules (e.g., “Does it have sufficient balance?”).
- Important: The Model knows nothing about HTML. It never does an
echo. It only returns raw data (Arrays or Objects).
This is what the user sees. It’s HTML code mixed with very little PHP (only to display variables).
- Receives data and renders it.
- Important: The View has no logic. It does not perform SQL queries or complex calculations. It is “dumb”.
It is the intermediary. The user never calls the Model or the View directly; they call the Controller.
- Receives the user’s request.
- Asks the Model for data.
- Loads the View and passes it the data to be displayed.
The Restaurant Analogy
To understand it better, imagine a restaurant:
You (User): You arrive and order a dish.
The Waiter (Controller): Takes your order. They don’t cook or grow the vegetables. They just coordinate.
The Kitchen (Model): The waiter takes the order to the kitchen. There, the chef finds the ingredients (Database), cooks them, and prepares the dish. The chef doesn’t know who will eat it or at which table.
The Plated Dish (View): The food is placed on a nice plate.
Outcome: The waiter (Controller) picks up the plate (View) with the prepared food (Model Data) and serves it to you.
Practical Code Example
Let’s see how a simple script that displays a user’s profile would be separated.
A. The Model (src/Models/User.php)
Only concerned with data.
namespace MyApp\Models;
class User {
public function getById($id) {
// Simulate a DB query
return [
'name' => 'Ana Garcia',
'email' => '[email protected]',
'role' => 'Admin'
];
}
}B. The View (views/profile.php)
Only concerned with displaying HTML. It doesn’t know where the data came from, only that a $data variable exists.
<!DOCTYPE html>
<html>
<body>
<h1>User Profile</h1>
<p>Name: <?= htmlspecialchars($data['name']) ?></p>
<p>Email: <?= htmlspecialchars($data['email']) ?></p>
</body>
</html>C. The Controller (src/Controllers/UserController.php)
Connects everything.
namespace MyApp\Controllers;
use MyApp\Models\User;
class UserController {
public function showProfile($id) {
// 1. Call the model to request data
$model = new User();
$data = $model->getById($id);
// 2. Load the view and "pass" the data to it
// (By using require, the view will have access to the $data variable)
require 'views/profile.php';
}
}Why complicate things so much?
At first, it seems like you’re writing more files to do the same thing, but the advantages are enormous:
- Maintainability: If you want to change the HTML design (View), you don’t touch or break the database logic (Model).
- Teamwork: A frontend designer can work on the View while the backend programmer works on the Model without interfering.
- Reusability: The same Model (
getUserfunction) can be used to display the profile on the web, in a PDF, or send it via an API, because it doesn’t have HTML attached.