Pregunta

¿Hay una manera de lanzar excepciones de un cargador automático de SPL en PHP en caso de que falle? No parecen funcionar bien en PHP 5.2.11.

class SPLAutoLoader{

    public static function autoloadDomain($className) {
        if(file_exists('test/'.$className.'.class.php')){
            require_once('test/'.$className.'.class.php');
            return true;
        }       

        throw new Exception('File not found');
    }

} //end class

//start
spl_autoload_register( array('SPLAutoLoader', 'autoloadDomain') );

try{
    $domain = new foobarDomain();
}catch(Exception $c){
    echo 'File not found';
}

Cuando el código de arriba se llama, no hay ninguna señal de una excepción, en vez consigo un estándar "Fatal error: Class 'foobarDomain' no se encuentra en bla". Y la ejecución de las secuencias de comandos termina.

¿Fue útil?

Solución

Esto no es un error, es una decisión de diseño :

  

Nota: : Excepciones lanzadas en función __autoload no pueden quedar atrapados en el bloque catch y resulta en un error fatal.

La razón es que no puede haber más de uno manipuladores de carga automática, en cuyo caso, que no desee el primer controlador de lanzar una excepción y omitir el segundo controlador. Usted quiere que su segundo manejador de tener la oportunidad de autoloading sus clases. Si utiliza una biblioteca que hace uso de la función de carga automática, que no quiere que pasar por el controlador de carga automática, ya que lanzar excepciones dentro de su cargador automático.

Si desea comprobar si está o no puede crear una instancia de una clase, a continuación, utilizar class_exists y pasar true como segundo argumento (o dejarlo fuera, true es el valor predeterminado):

if (class_exists('foobarDomain', $autoload = true)) {
    $domain = new foobarDomain();
} else {
    echo 'Class not found';
}

Otros consejos

De acuerdo con los comentarios en la documentación para spl_autoload_register , es posible llamar a otra función del cargador automático, que a su vez emitir la excepción.

class SPLAutoLoader{

    public static function autoloadDomain($className) {
        if(file_exists('test/'.$className.'.class.php')){
            require_once('test/'.$className.'.class.php');
            return true;
        }       
        self::throwFileNotFoundException();
    }

    public static function throwFileNotFoundException()
    {
        throw new Exception('File not found');
    }

} //end class

//start
spl_autoload_register( array('SPLAutoLoader', 'autoloadDomain') );

try{
    $domain = new foobarDomain();
}catch(Exception $c){
    echo 'File not found';
}

Aquí está un objeto de pleno derecho de la fábrica que demuestra la auto-carga, soporte de espacios de nombres, callables de casos no estáticos (con las trayectorias variables), el manejo de errores de carga y excepciones personalizadas.

abstract class AbstractFactory implements \ArrayAccess
{
    protected $manifest;
    function __construct($manifest)
    {
        $this->manifest = $manifest;
    }

    abstract function produce($name);

    public function offsetExists($offset)
    {
        return isset($this->manifest[$offset]);
    }

    public function offsetGet($offset)
    {
        return $this->produce($offset);
    }
    //implement stubs for other ArrayAccess funcs
}


abstract class SimpleFactory extends AbstractFactory {

    protected $description;
    protected $path;
    protected $namespace;

    function __construct($manifest, $path, $namespace = "jj\\") {
        parent::__construct($manifest);
        $this->path = $path;
        $this->namespace = $namespace;
        if (! spl_autoload_register(array($this, 'autoload'), false)) //throws exceptions on its own, but we want a custom one
            throw new \RuntimeException(get_class($this)." failed to register autoload.");
    }

    function __destruct()
    {
        spl_autoload_unregister(array($this, 'autoload'));
    }

    public function autoload($class_name) {
        $file = str_replace($this->namespace, '', $class_name);
        $filename = $this->path.$file.'.php';
        if (file_exists($filename))
            try {
                require $filename; //TODO add global set_error_handler and try clause to catch parse errors
            } catch (Exception $e) {} //autoload exceptions are not passed by design, nothing to do
    }

    function produce($name) {
        if (isset($this->manifest[$name])) {
            $class = $this->namespace.$this->manifest[$name];
            if (class_exists($class, $autoload = true)) {
                return new $class();
            } else throw new \jj\SystemConfigurationException('Factory '.get_class($this)." was unable to produce a new class {$class}", 'SYSTEM_ERROR', $this);
//an example of a custom exception with a string code and data container

        } else throw new LogicException("Unknown {$this->description} {$name}.");
    }

    function __toString() //description function if custom exception class wants a string explanation for its container
    {
        return $this->description." factory ".get_class($this)."(path={$this->path}, namespace={$this->namespace}, map: ".json_encode($this->manifest).")";
    }

}

y, finalmente, un ejemplo:

namespace jj;
require_once('lib/AbstractFactory.php');
require_once('lib/CurrenciesProvider.php'); //base abstract class for all banking objects that are created

class CurrencyProviders extends SimpleFactory
{
    function __construct()
    {
        $manifest = array(
          'Germany' => 'GermanBankCurrencies',
          'Switzerland' => 'SwissBankCurrencies'
        );

        parent::__construct($manifest, __DIR__.'/CurrencyProviders/', //you have total control over relative or absolute paths here
       'banks\');
        $this->description = 'currency provider country name';
    }


}

Ahora hacer

$currencies_cache = (new \jj\CurrencyProviders())['Germany'];

o

$currencies_cache = (new \jj\CurrencyProviders())['Ukraine'];
  

LogicException ( "nombre del país proveedor de moneda Desconocido Ucrania")

Si no hay ningún archivo en SwissCurrencies.php / CurrencyProviders /,

  

\ jj \ SystemConfigurationException ( "fábrica jj \ CurrencyProviders fue incapaz de producir una nueva clase bancos \ SwissCurrencies datos de depuración:. Moneda del país proveedor de nombre de la fábrica jj \ CurrencyProviders (path = / var / www / alojada / site / ... / CurrencyProviders /, espacio de nombres = bancos \, mAP: { "Alemania": "GermanBankCurrencies", "Suiza": ""} SwissBankCurrencies ')

Con bastante esfuerzo esta fábrica se puede extender a errores de análisis de captura ( Como el error de captura de require () o incluir () en PHP? ) y pasar argumentos a los constructores.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top