Question

Est-il possible de lever des exceptions à partir d'un SPL autochargeur en PHP dans le cas où il échoue? Il ne semble pas fonctionner sous 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';
}

Lorsque le code ci-dessus est appelé, il n'y a aucun signe d'une exception, au lieu que je reçois une norme « Erreur fatale: de la foobarDomain 'Classe introuvable Bla ». Et l'exécution du script se termine.

Était-ce utile?

La solution

Ce n'est pas un bug, il est une décision de conception :

  

Remarque : Les exceptions levées en fonction __autoload ne peuvent pas être pris dans le bloc catch et provoque une erreur fatale.

La raison en est qu'il peut y avoir plus d'un gestionnaire d'autoload, auquel cas, vous ne voulez pas le premier gestionnaire de lancer une exception et court-circuiter le second gestionnaire. Vous voulez que votre deuxième gestionnaire d'avoir une chance de autoloading ses classes. Si vous utilisez une bibliothèque qui utilise la fonction de chargement automatique, vous ne voulez pas passer par votre gestionnaire de chargement automatique, car ils jettent des exceptions dans leur chargeur automatique.

Si vous voulez vérifier si vous pouvez ou non instancier une classe, puis utilisez

Autres conseils

D'après les commentaires dans la documentation spl_autoload_register , il est possible d'appeler une autre fonction du chargeur automatique, ce qui jetterait l'exception.

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';
}

Voici un objet usine à part entière qui démontre l'auto-chargement, support des espaces de noms appelables des instances non statiques (avec des chemins variables), le traitement des erreurs de chargement et exceptions personnalisées.

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).")";
    }

}

et enfin un exemple:

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';
    }


}

maintenant faire

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

ou

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

LogicException ( "nom du pays fournisseur de monnaie inconnue Ukraine")

S'il n'y a pas de fichier dans SwissCurrencies.php / CurrencyProviders /,

  

\ fg \ SystemConfigurationException ( 'usine ndj \ CurrencyProviders n'a pas pu produire une nouvelle banques de classe \ SwissCurrencies Les données de débogage:. Nom du pays fournisseur de monnaie usine mau \ CurrencyProviders (path = / var / www / / site / ... / CurrencyProviders /, namespace = banques \ map: { "Allemagne": "GermanBankCurrencies", "Suisse": "SwissBankCurrencies"})

Avec assez d'effort cette usine peut être étendue pour attraper des erreurs d'analyse ( Comment attraper erreur de require () ou include () en PHP? ) et passer des arguments aux constructeurs.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top