Бросая исключения в автозазагрузку SPL?

StackOverflow https://stackoverflow.com/questions/1579080

  •  21-09-2019
  •  | 
  •  

Вопрос

Есть ли способ выбросить исключения из автозазагрузчика SPL в PHP на случай, если он не удастся? Кажется, это не работает в соответствии с 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';
}

Когда приведен выше код, нет никаких признаков исключения, вместо этого я получаю стандартную «фатальную ошибку: класс» foobardomain 'не найден в BLA ». И выполнение скрипта завершается.

Это было полезно?

Решение

Это не ошибка, это дизайнерское решение:

Примечание: Исключения брошены __autoload функция не может быть пойман в catch Блок и приводит к смертельной ошибке.

Причина в том, что может быть более одного обработчика автозагрузки, и в этом случае вы не хотите, чтобы первый обработчик бросил исключение и обошла второго обработчика. Вы хотите, чтобы у вашего второго обработчика был шанс автоматически загружать свои занятия. Если вы используете библиотеку, которая использует функцию автозагрузки, вы не хотите, чтобы она обходила ваш обработчик автозагрузки, потому что они бросают исключения внутри своего автозагрузки.

Если вы хотите проверить, можете ли вы создать экземпляр класса, то используйте class_exists и пройти true как второй аргумент (или оставляйте, true по умолчанию):

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

Другие советы

Согласно комментариям в Документация для spl_autoload_register, можно вызвать другую функцию от автозагрузчика, что, в свою очередь, выставит исключение.

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

Вот полноценный заводский объект, который демонстрирует автоматическую загрузку, поддержку пространств имен, призывы к нестатическим экземплярам (с переменными путями), обработку ошибок загрузки и пользовательские исключения.

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

}

И, наконец, пример:

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


}

Теперь делай

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

или же

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

Logicexception («Неизвестный поставщик валют название страны Украина»)

Если нет файла swisscurrenties.php в /валютных провидеров /,

jj SystemConfigurationException ('Factory JJ VurrancePiders не смог создать новые банки классов Swisscurrences. Данные отладки: поставщик валют. Имя страны Фабрика jj VurrancePiders (PATH =/var/www/Hosted/Site /.../ VARUNTYPIDERS/ , namespace = Banks , Map: {"Germany": "GermanbankCurrentries", "Switzerland": "Swissbankcurrents"} ')

С достаточными усилиями эта фабрика может быть расширена, чтобы поймать ошибки анализа (Как поймать ошибку require () или включить () в php?) и передавать аргументы конструктору.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top