Si has trabajado con programación orientada a objetos en PHP y eres un poco ordenado/a seguramente crearás un fichero independiente para cada una de las clases. Es la opción más recomendable. Sin embargo ello te obligará a utilizar de forma reiterada la función require_once()
o similar para cargar cada una de las clases en los distintos ficheros de tu proyecto, lo cual resulta pesado y aburrido.
Para resolver este problema utilizaremos la carga automática de clases de PHP 5: __autoload()
o spl_autoload_register()
.
La función de carga básica
Leyendo la documentación oficial vemos que lo que hace la función __autoload()
es dar una oportunidad para realizar una acción antes de que el compilador de PHP arroje un error al no encontrar una clase o interface instanciada durante la ejecución. El ejemplo más claro lo podemos ver en este ejemplo tomado de la documentación oficial.
<?php function __autoload($nombre_clase) { require_once("classes/" . $nombre_clase . '.php'); } $obj = new MiClase1(); $obj2 = new MiClase2(); |
Como vemos la función lo que hace cuando no encuentra la clase que instanciamos unas líneas más abajo es buscar los ficheros classes/MiClase1.php
y classes/MiClase2.php
. En caso de no encontrarlos nos arrojará un Fatal Error dado que utilizamos la función require_once()
.
Inconvenientes de __autoload()
Sin embargo, y como leerás en la documentación oficial de PHP está desaconsejado su uso. Esto es debido a que cada clase que se carga pasa por esta función y en algún desarrollo grande puede arrojar fallos debido a que se ha podido definir en alguna otra parte del proyecto y puede que busque los ficheros en directorios erróneos y falle la ejecución del código.
Os recomiendo que la leáis pues aporta bastantes ejemplos en el uso de __autoload(), incluyendo el manejo de excepciones.
La función spl_autoload_register()
Para evitar que todas las clases pasen por __autoload()
existe la opción de utilizar la función spl_autoload_register()
que nos permite registrar distintas funciones de autoload o carga automática de clases, añadiéndolas a la cola de __autoload()
.
Esto puede ser especialmente útil si aprovechamos otra funcionalidad de programación orientada a objetos: los namespaces. Si no los conoces te vendrá bien la documentación oficial sobre namespaces en PHP 5.
Cuando recuperamos la variable $nombre_clase
observaremos que si hemos utilizamos namespaces el nombre de todas las clases viene precedido de su correspondiente namespace.
Tomemos como ejemplo una clase creada con el siguiente código:
<?php namespace OG; class Ejemplo { public function __construct () { } } |
Cuando llega a nuestra función de carga automática lo hace con el nombre OG\Ejemplo. Esto no sólo nos permite aislar la ejecución de código en distintos namespaces, sino aprovecharnos de ello para poder especificar distintos directorios de lectura del fichero de la clase en función del namespace.
Cuando necesito la carga de clases específicas en cualquier proyecto utilizo este sistema para la carga de clases. De este modo me permite tener mi código convenientemente ordenado en clases y su ejecución aislada del resto de proyecto.
La mayoría de frameworks como Laravel, Zend, etc ya tienen implementado este sistema. Sin embargo otros entornos como WordPress carecen de él, así que todo se ejecuta en el mismo espacio de nombres. Una práctica nada recomendable.
Veamos un ejemplo de cómo podríamos implementar este código:
// Classes autoload OG spl_autoload_register('OG_autoload'); function OG_autoload($classname) { $namespace = explode("\\" , $classname)[0]; if ($namespace == 'OG') { $classname = str_replace ('\\', '/', $classname); $filename = "classes/". $classname .".class.php"; require_once( __DIR__ . '/' . $filename); } } |
En mi caso todas las librerías y clases que implemento en mis desarrollos las incluyo en el namespace OG. Si en el nombre de la clase a cargar detecto que se encuentra en dicho namespace procedo a ejecutar el resto del código. Para ello simplemente busco cada una de las clases dentro de su correspondiente directorio.
Si utilizaramos distintas jerarquías dentro de los espacios de nombre como OG\Subnivel1\Subnivel2 simplemente deberemos de respetar los niveles de anidación creando nuevos subdirectorios en donde almacenar los ficheros con las correspondientes clases.
Si habéis programado con algún framework como Symfony, Zend o Laravel este es el sistema de carga de clases que utilizan y no os resultará desconocido.
Conclusión
A la hora de programar lo ideal es automatizar al máximo nuestro trabajo evitándonos tareas tediosas como la carga y búsqueda de clases y/o ficheros. Para ello PHP 5 nos ofrece funciones muy sencillas dentro de la Standard PHP Library que facilitan esta tarea. Además unido a la ejecución de código en namespaces aún hace nuestro código más sencillo de entender, ordenado y reutilizable.
Si trabajas en algunos entornos como WordPress en el que interactuan miles de plugins y funciones diferentes corres el riesgo de declarar nombres de clases que quizás alguien ya haya utilizado. Para ello es fundamental el uso de namespaces para declarar espacios de ejecución separados.
Este es sólo un sencillo ejemplo, que por supuesto se podría mejorar. Encantado de recibir sugerencias y mejoras.
Fuentes
Autor:
Última actualización:
Mola el artículo 🙂
Es interesante que la gente sepa cómo definir un autoloader para cuando se trabaja en proyectos con CMSs como WordPress, para poder cargar las clases de tu plugin.
No obstante se echa en falta alguna mención a los estándares de autoloading y al autoloader de composer.
http://www.php-fig.org/psr/psr-4/
https://getcomposer.org/doc/01-basic-usage.md#autoloading
Casi todos los frameworks están dejando de definir sus propios complementos de autoloading en beneficio de composer, que ha demostrado ser de los más eficientes y fáciles de configurar.
Muchas gracias Alejandro! 🙂 Muy bueno el apunte.
Tengo que estudiar con más tiempo composer dado que generalmente sigo los manuales de instalación de librerías y poco más.
¿Para cuando una segunda edición de tu charla sobre composer? 😀
Jajaja. No se, no se… Ya veremos