Como implementar un autoload de clases en PHP


Cuando escribimos código de PHP, lo usual es que tengamos nuestro código organizado en diferentes archivos, esto hace que el código este mejor ordenado y que darle mantenimiento sea más fácil. Pero esto genera un problema nuevo… Debes agregar cada archivo con una sentencia require o equivalente.

Para solventar este nuevo problema se puede crear un programa para auto cargar cada clase que vayas a usar y esto se logra con la función spl_autoload_register de PHP. Veamos ahora como se utiliza.

Utilizar la función spl_autoload_register puede ser un poco confuso, entonces para facilitarte la vida puedes simplemente utilizar esta clase genérica que te ayudará a cargar automáticamente cualquier clase que necesites. Para usarla crea un archivo llamado Loader.php y agrega este código:

<?php

/**
 * Clase para cargar automaticamente
 * cualquier otra clase que necesites en tu codigo.
 */
class  Loader
{
  protected static $dirs = array();
  protected static $registered = 0;

  public function __construct($dirs = array())
  {
      self::init($dirs);
  }

  protected static function loadFile($file)
  {
      if (file_exists($file)) {
          require_once $file;
          return TRUE;
      }
      return FALSE;
  }

  public static function autoLoad($class)
  {
      $success = FALSE;
      $fn = str_replace('\\', DIRECTORY_SEPARATOR, $class)
            . '.php';
      foreach (self::$dirs as $start) {
          $file = $start . DIRECTORY_SEPARATOR . $fn;
          if (self::loadFile($file)) {
              $success = TRUE;
              break;
          }
      }
      if (!$success) {
          if (!self::loadFile(__DIR__
              . DIRECTORY_SEPARATOR . $fn)) {
              throw new \Exception(
                  'No se puede cargar la clase:  ' . $class);
          }
      }
      return $success;
  }

  public static function addDirs($dirs)
  {
      if (is_array($dirs)) {
          self::$dirs = array_merge(self::$dirs, $dirs);
      } else {
        self::$dirs[] = $dirs;
     }
  }

  public static function init($dirs = array())
  {
      if ($dirs) {
          self::addDirs($dirs);
      }
      if (self::$registered == 0) {
          spl_autoload_register(__CLASS__ . '::autoload');
          self::$registered++;
      }
  }

} // fin de la clase


 ?>

Ejemplo de Autoload de clases en PHP

Ahora necesitamos probar si funciona. Primero crea una estructura de archivos como esta:

Estructura de archivos para probar autoload de clases en PHP

Ya tienes el archivo Loader.php, ahora vamos a crear una clase sencilla para probar si la clase se carga de forma automática, entonces crea un archivo llamado TestClass.php dentro de la carpeta test, con este código:

<?php
namespace test;
class TestClass
{
    public function getTest()
    {
        return "Funciona!!!!";
    }
}

Ahora crea un archivo llamado index.php para probar el código:

<?php
require __DIR__ . '/Loader.php';
Loader::init( );

$test = new Test\TestClass();
echo $test->getTest();

Ahora ejecuta el archivo index.php y si todo funciona veras algo como esto, en tu pantalla:

Ejemplo de función spl_autoload_register en php

Autoload de clases: Definir carpetas para búsqueda.

En el ejemplo anterior la clase que se auto cargo, estaba en una carpeta que coincide con el namespace de la clase, esto hace que sea fácil encontrar el archivo que se debe cargar para poder usar la clase. Pero que pasa si usamos una estructura de carpetas más complicada, por ejemplo colocando todo dentro una carpeta llamada src.

Vamos a trabajar con esta otra estructura de archivos, en donde tenemos que cargar las clases que estén dentro de la carpeta src.

Estructura de carpetas para ejemplo de auto carga de clases en php

Ahora crea una clase con este código en el archivo file.php

<?php

namespace files;
class file
{
  function check()
  {
    return "Si existe";
  }
}

Ahora cambia el contenido del archivo index.php con este otro código:

<?php
require __DIR__ . '/Loader.php';
Loader::init(__DIR__.'/src' );

$files = new files\file();
echo $files->check();
 

La diferencia es que en la función Loader::init( ) ahora pasamos una carpeta en la que hay que buscar archivos de clases, este parámetro puede ser un Array para que puedas enviar varias rutas posibles para buscar archivos de clases.

Algunas restricciones.

Para que este código funcione cada archivo debe contener solo una clase, lo cual es una de las buenas practicas al escribir código. Y también el archivo debe de tener el mismo nombre de la clase, lo cual es también una buena practica.