Las plantillas de PHP a menudo tienen una mala reputación por facilitar un código deficiente, pero ese no tiene por qué ser el caso. Veamos cómo los proyectos PHP pueden imponer una estructura básica de Modelo, Vista, Controlador (MVC) sin depender de un motor de plantillas especialmente diseñado.
Pero primero, una breve lección de historia de PHP
La historia de PHP como herramienta para la creación de plantillas HTML está llena de giros y vueltas.
Uno de los primeros lenguajes de programación utilizados para la creación de plantillas HTML fue C, pero rápidamente se descubrió que su uso resultaba tedioso y, en general, inadecuado para la tarea.
Rasmus Lerdorf creó PHP con esto en mente. No se oponía a utilizar C para manejar la lógica empresarial de back-end, pero quería una mejor manera de generar HTML dinámico para el front-end. PHP fue diseñado originalmente como un lenguaje de plantillas, pero adoptó más funciones con el tiempo y finalmente se convirtió en un lenguaje de programación completo por derecho propio.
Se descubrió que la capacidad única de PHP para cambiar entre el modo de programación y el modo HTML era bastante conveniente, pero también hacía tentador para los programadores escribir código inmantenible, código que mezclaba lógica empresarial y lógica de plantillas. Un archivo PHP podría comenzar con algunas plantillas HTML y luego sumergirse repentinamente en una consulta SQL avanzada sin previo aviso. Esta estructura es confusa de leer y dificulta la reutilización de plantillas HTML.
A medida que pasaba el tiempo, la comunidad de desarrollo web encontró cada vez más valor imponiendo una estructura MVC estricta para proyectos PHP. Los motores de plantillas se crearon como una forma de separar eficazmente las vistas de sus controladores.
Para realizar esta tarea, los motores de creación de plantillas suelen tener las siguientes características:
- El motor tiene poca potencia a propósito para la lógica empresarial. Si un desarrollador desea realizar una consulta de base de datos, por ejemplo, necesita realizar esa consulta en el controlador y luego pasar el resultado a la plantilla. Hacer una consulta en medio del HTML de la plantilla no es una opción.
- El motor se encarga de los riesgos de seguridad comunes entre bastidores. Incluso si un desarrollador no puede validar la entrada del usuario y la pasa directamente a la plantilla, la plantilla a menudo escapará automáticamente de cualquier HTML peligroso.
Los motores de plantillas son ahora una característica fundamental en muchas pilas de tecnología web. Hacen que las bases de código sean más fáciles de mantener y más seguras, por lo que esto no es ninguna sorpresa.
Sin embargo, es posible manejar plantillas HTML con PHP simple también. Es posible que desee hacer esto por varias razones. Tal vez esté trabajando en un proyecto heredado y no quiera incorporar dependencias adicionales, o tal vez esté trabajando en un proyecto muy pequeño y prefiera mantener las cosas lo más livianas posible. O tal vez la decisión no depende de usted en absoluto.
Casos de uso para plantillas PHP
Un lugar en el que a menudo implemento plantillas PHP simples es WordPress, que no aplica una estructura MVC rígida de forma predeterminada. Siento que incorporar un motor de plantillas completo es un poco torpe, pero aún quiero separar mi lógica comercial de mis plantillas y quiero que mis vistas sean reutilizables.
Cualquiera sea su razón, usar PHP simple para definir sus plantillas HTML es a veces la opción preferida. Esta publicación explora cómo se puede hacer esto de una manera razonablemente profesional. El enfoque representa un punto medio práctico entre el estilo codificado como espagueti por el que las plantillas PHP se han vuelto famosas y el enfoque sin lógica permitida disponible con los motores de plantillas formales.
Veamos un ejemplo de cómo se puede poner en práctica un sistema básico de plantillas. Nuevamente, estamos usando WordPress como ejemplo, pero esto podría cambiarse a un entorno PHP simple o muchos otros entornos. Y no necesita estar familiarizado con WordPress para seguirlo.
El objetivo es dividir nuestras vistas en componentes y crear una separación clara entre la lógica empresarial y las plantillas HTML. Específicamente, vamos a crear una vista que muestre una cuadrícula de tarjetas. Cada tarjeta mostrará el título, el extracto y el autor de una publicación reciente.
Paso 1: obtener datos para renderizar
El primer paso a tomar es obtener los datos que queremos mostrar en nuestra vista. Esto podría implicar ejecutar una consulta SQL o usar el ORM o las funciones auxiliares de su marco / CMS para acceder a su base de datos indirectamente. También podría implicar realizar una solicitud HTTP a una API externa o recopilar la entrada del usuario desde un formulario o una cadena de consulta.
En este ejemplo, usaremos WordPress get_posts
función de ayuda para buscar algunas publicaciones para mostrar en nuestra página de inicio.
<?php // index.php
$wp_posts = get_posts([
'numberposts' => 3
]);
Ahora tenemos acceso a los datos que queremos mostrar en la cuadrícula de tarjetas, pero necesitamos hacer un trabajo adicional antes de poder pasarlos a nuestra vista.
Paso 2: preparación de datos para la creación de plantillas
El get_posts
la función devuelve una matriz de WP_Post
objetos. Cada objeto contiene el título de la publicación, el extracto y la información del autor que necesitamos, pero no queremos acoplar nuestra vista a la WP_Post
tipo de objeto porque es posible que deseemos mostrar otros tipos de datos en nuestras tarjetas en algún otro lugar del proyecto.
En cambio, tiene sentido convertir proactivamente cada objeto de publicación en un tipo de datos neutral, como una matriz asociativa:
<?php // index.php
$wp_posts = get_posts([
'numberposts' => 3
]);
$cards = array_map(function ($wp_post) {
return [
'heading' => $wp_post->post_title,
'body' => $wp_post->post_excerpt,
'footing' => get_author_name($wp_post->post_author)
];
}, $wp_posts);
En este caso, cada WP_Post
El objeto se convierte en una matriz asociativa mediante el uso de array_map
función. Observe que las claves para cada valor no son title
, excerpt
, y author
pero se les dan nombres más generales en su lugar: heading
, body
, y footing
. Hacemos esto porque el componente de cuadrícula de tarjetas está destinado a admitir cualquier tipo de datos, no solo publicaciones. Podría usarse fácilmente para mostrar una cuadrícula de testimonios que tengan una cotización y el nombre de un cliente, por ejemplo.
Con los datos preparados correctamente, ahora se pueden pasar a nuestro render_view
función:
<?php // index.php
// Data fetching and formatting same as before
render_view('cards_grid', [
'cards' => $cards
]);
Por supuesto, el render_view
la función aún no existe. Vamos a definirlo.
Paso 3: crear una función de renderizado
// Defined in functions.php, or somewhere else that will make it globally available.
// If you are worried about possible collisions within the global namespace,
// you can define this function as a static method of a namespaced class
function render_view($view, $data)
{
extract($data);
require('views/' . $view . '.php');
}
Esta función acepta el nombre de la vista renderizada y una matriz asociativa que representa cualquier dato que se mostrará. La función de extracción toma cada elemento de la matriz asociativa y crea una variable para él. En este ejemplo, ahora tenemos una variable llamada $cards
que contiene los elementos que preparamos en index.php
.
Dado que la vista se ejecuta en su propia función, obtiene su propio alcance. Esto es bueno porque nos permite usar nombres de variables simples sin temor a colisiones.
La segunda línea de nuestra función imprime la vista que coincide con el nombre pasado. En este caso, busca la vista en views/cards_grid.php
. Sigamos adelante y creemos ese archivo.
Paso 4: creación de plantillas
<?php /* views/cards_grid.php */ ?>
<section>
<ul>
<?php foreach ($cards as $card) : ?>
<li>
<?php render_view('card', $card) ?>
</li>
<?php endforeach; ?>
</ul>
</section>
Esta plantilla utiliza el $cards
variable que se acaba de extraer y la presenta como una lista desordenada. Para cada carta de la matriz, la plantilla representa una subvista: la vista de carta singular.
Tener una plantilla para una sola tarjeta es útil porque nos da la flexibilidad de renderizar una sola tarjeta directamente o usarla en otra vista en otra parte del proyecto.
Definamos la vista básica de la tarjeta:
<?php /* views/card.php */ ?>
<div class="card">
<?php if (!empty($heading)) : ?>
<h4><?= htmlspecialchars($heading) ?></h4>
<?php endif;
if (!empty($body)) : ?>
<p><?= htmlspecialchars($body) ?></p>
<?php endif;
if (!empty($footing)) : ?>
<span><?= htmlspecialchars($footing) ?></span>
<?php endif; ?>
</div>
Desde el $card
que se pasó a la función de renderizado contenía claves para un heading
, body
, y footing
, las variables con esos mismos nombres ahora están disponibles en la plantilla.
En este ejemplo, podemos estar razonablemente seguros de que nuestros datos están libres de peligros XSS, pero es posible que esta vista se pueda usar con la entrada del usuario en algún momento posterior, por lo que pasar cada valor a través de htmlspecialchars
es prudente. Si existe una etiqueta de secuencia de comandos en nuestros datos, se escapará de forma segura.
También suele ser útil comprobar que cada variable contiene un valor no vacío antes de representarlo. Esto permite omitir variables sin dejar etiquetas HTML vacías en nuestro marcado.
Los motores de plantillas PHP son excelentes, pero a veces es apropiado usar PHP para lo que fue diseñado originalmente: generando HTML dinámico.
La creación de plantillas en PHP no tiene por qué resultar en un código espagueti que no se pueda mantener. Con un poco de previsión, podemos lograr un sistema MVC básico que mantenga las vistas y los controladores separados entre sí, y esto se puede hacer con un código sorprendentemente pequeño.