Una guía para estructurar tu backend con claridad, orden y escalabilidad
Cuando desarrollamos aplicaciones web, especialmente en PHP u otros lenguajes interpretados, podemos caer fácilmente en el caos si no seguimos una estructura bien definida.
Uno de los pilares para construir una aplicación clara y mantenible es establecer un controlador central o main
, que orqueste el flujo de ejecución, reciba peticiones, controle la navegación y administre la interacción con el usuario.
En este artículo vamos a construir paso a paso ese núcleo central de nuestra aplicación PHP, explorando también cómo este patrón es utilizado tanto en frameworks backend como Laravel y CodeIgniter, como en tecnologías frontend como Angular o React. Además, veremos por qué esta filosofía trasciende el lenguaje y se aplica también en sistemas compilados o arquitecturas desacopladas.
🎯 ¿Qué es un «Controlador Central»?
Un controlador central (front controller o main controller) es un único punto de entrada que:
- Recibe y procesa todas las solicitudes del usuario
- Muestra la vista general y las opciones disponibles
- Interpreta acciones o eventos
- Llama a los modelos necesarios para obtener o guardar datos
- Deriva tareas a subcontroladores especializados
- Mantiene el flujo de la aplicación mientras el usuario interactúa
Este controlador es la mente de la aplicación: no resuelve todo por sí solo, pero es quien decide a quién le toca actuar.
🧱 Estructura básica del proyecto
Organizamos nuestra aplicación en carpetas separadas para controladores, modelos, vistas y configuraciones.
/app
/controllers
/models
/views
main.php
autoload.php
config.php
// main.php (Controlador Central)
session_start();
require_once "config.php";
require_once "autoload.php";
$controller = new MainController();
$controller->run();
Aquí MainController
es la clase que controla el flujo general.
⚙️ Implementando el flujo en MainController
class MainController {
public function run() {
$this->showLayoutHeader(); // Cabecera, menús
$this->processRequest(); // Lógica principal
$this->showLayoutFooter(); // Pie de página
}
private function showLayoutHeader() {
include "views/layout/header.php";
}
private function showLayoutFooter() {
include "views/layout/footer.php";
}
private function processRequest() {
$action = $_GET['action'] ?? 'home';
$this->dispatch($action);
}
private function dispatch($action) {
switch($action) {
case 'login':
require_once "controllers/LoginController.php";
$controller = new LoginController();
$controller->handle();
break;
case 'dashboard':
require_once "controllers/DashboardController.php";
$controller = new DashboardController();
$controller->handle();
break;
default:
include "views/home.php";
}
}
}
Este enfoque permite dividir el comportamiento en subcontroladores especializados (por ejemplo, LoginController
, DashboardController
, etc.) y mantener limpio el núcleo.
🔐 Ejemplo: Controlador para Login
// controllers/LoginController.php
class LoginController {
public function handle() {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['user'] ?? '';
$password = $_POST['pass'] ?? '';
$auth = new AuthModel();
if ($auth->check($username, $password)) {
$_SESSION['user'] = $username;
header('Location: ?action=dashboard');
exit;
} else {
$error = "Credenciales incorrectas";
include "views/login.php";
}
} else {
include "views/login.php";
}
}
}
Con este modelo, puedes añadir lógica para registro, cierre de sesión, edición de perfil, etc., sin romper la estructura general.
🔁 Flujo continuo e interacción
Este patrón mantiene el flujo de ejecución activo. Cada interacción (click, envío de formulario, navegación) pasa por main.php
, que reinterpreta el contexto y llama al controlador correspondiente.
Este flujo puede mejorarse aún más usando AJAX, lo que permite:
- Evitar recargas completas de página
- Actualizar solo partes específicas del contenido
- Mantener el “ciclo de interacción” en el navegador
🧩 Esta arquitectura vive en todos los frameworks
Aunque esta estructura puede parecer artesanal, en realidad es el corazón de todos los grandes frameworks.
🧱 Backend: Laravel, CodeIgniter, Symfony…
Estos frameworks tienen un único punto de entrada (index.php
) que:
- Recibe cada solicitud.
- La interpreta mediante un sistema de enrutamiento.
- Llama al controlador adecuado.
- Devuelve una vista o un JSON.
Nosotros lo hacemos manualmente con un switch
, ellos lo hacen mediante clases Router, Middleware, Service Containers… pero la lógica es exactamente la misma.
🖥 Frontend: Angular, Vue, React…
En frameworks frontend modernos, el controlador central ya no está en el backend, sino en el navegador:
- Angular usa
AppComponent
yRouterModule
para cargar vistas y gestionar rutas. - React utiliza
React Router
para manejar vistas y navegación dinámica. - Vue maneja rutas con
vue-router
.
Todos tienen un núcleo que interpreta la navegación, renderiza vistas, maneja eventos y carga datos desde APIs. Es decir: tienen su propio «main controller» embebido en el cliente.
🔄 Cuando el frontend controla y el backend reacciona
En aplicaciones modernas, el frontend (como Angular) puede encargarse completamente del flujo de la app y el backend (Laravel, CodeIgniter, etc.) se limita a responder solicitudes API.
Aquí cambia el paradigma:
Rol | Arquitectura Tradicional | SPA con Angular |
---|---|---|
Controlador central | PHP (main.php ) | Angular (AppComponent , Router ) |
Flujo de ejecución | En el servidor | En el navegador |
Backend | Conduce el flujo | Responde peticiones (API REST) |
El backend ya no es proactivo ni decide qué vista mostrar: solo devuelve datos cuando el frontend los solicita.
Se convierte en un backend reactivo, es decir, en un servidor de APIs.
🧠 Un principio universal: el «main» existe en todo lenguaje
En lenguajes compilados como C, Java, Rust o Go, el punto de entrada (main()
) es obligatorio. Define dónde empieza el programa y cómo fluye la ejecución. ¡Sin él, simplemente no compila!
En lenguajes de scripting como PHP, Python o Perl, cada archivo puede ejecutarse por separado, lo que permite gran flexibilidad, pero también puede llevar a caos si no hay estructura.
Por eso, en proyectos reales y complejos, aunque el lenguaje no lo exija, los desarrolladores implementan un «main controller» igualmente.
Esto permite:
- Centralizar el control.
- Mejorar la claridad del código.
- Asegurar orden y escalabilidad.
Ya sea en PHP, Python, Node.js, Ruby o cualquier otro entorno, el patrón de «un punto de entrada principal que distribuye la ejecución» es una buena práctica transversal.
🏁 ¡Así que necesitas «un jefe» en tu proyecto!
El «controlador central» es mucho más que una estructura útil: es una filosofía de diseño de software.
Ya sea en aplicaciones simples o complejas, con o sin frameworks, en backend o frontend, organizar el flujo desde un núcleo principal te permite:
- Pensar de forma modular.
- Escalar sin perder control.
- Depurar con mayor facilidad.
- Enseñar y aprender con más claridad.
Es una herramienta esencial para todo desarrollador web backend que quiera construir aplicaciones ordenadas y sostenibles.