За последние 24 часа нас посетили 22540 программистов и 1211 роботов. Сейчас ищут 724 программиста ...

Генерирование ошибок при автолоаде классов

Тема в разделе "Прочие вопросы по PHP", создана пользователем Krasilich, 18 май 2010.

  1. Krasilich

    Krasilich Активный пользователь

    С нами с:
    12 фев 2010
    Сообщения:
    14
    Симпатии:
    0
    Привет.

    Неожиданно для себя столкнулся с проблемой, решил посоветоваться, как лучше решить.

    Я с помощью spl_autoload_register() зарегистрировал статический метод класса как автолоадер, все отлично работает, но есть одно но...

    Если функция не находит нужный файл - я получаю фатал, мол не найден указанный класс.

    Мне нужно что бы в этом случае бросалось исключение, это в идеале. Но, думаю, подойдет любой вариант, который позволит системе обрабатывать полученную ошибку, а не просто вылетать с фаталом.

    Как пишут на php.net в версиях пыха до 5.3 ислючения в автолоад функциях, скажем так, игнорируються, в 5.3.0+ все работает нормально.

    Конечно, понимаю, что это еще один повод проапдейтится, но я пока работаю с 5.2.11

    Заранее благодарен за советы.
     
  2. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    где-то на хабре читал статью в которой делается отлов всех ошибок каких только можно.
     
  3. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    ну так если разработчики как так скажем говорят что так скажем игнорируются исключения, то какие вопросы тогда?
     
  4. Krasilich

    Krasilich Активный пользователь

    С нами с:
    12 фев 2010
    Сообщения:
    14
    Симпатии:
    0
    Имееться ввиду что невозможно в самом автолоадере бросить исключение и потом его закетчить.

    Но я просто не верю в то, что нету способов обработки ошибок автолоада=)

    trigger_error() тоже не сработал...
     
  5. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    Krasilich
    есть скрытие фатал. Что ты хочешь делать когда класс не нейдётся?
     
  6. Krasilich

    Krasilich Активный пользователь

    С нами с:
    12 фев 2010
    Сообщения:
    14
    Симпатии:
    0
    Костян

    Идея в том, что бы показывать "красивое" или общее сообщение об ошибке.
     
  7. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    PHP:
    1. <?php
    2.  
    3. function autoload_scan_dirs($dirs_str, &$list)
    4. {
    5.     $dirs = explode(':', $dirs_str);
    6.  
    7.     foreach($dirs as $dir)
    8.     {
    9.         $elements = scandir(ROOT_PATH.$dir) or trigger_error('Error. Function: autoload_scan_dirs(). Directory "'.ROOT_PATH.$dir.'" not found.');
    10.  
    11.         unset($elements[0], $elements[1]);
    12.  
    13.         foreach($elements as $element) if(is_dir(ROOT_PATH.$path = $dir.'/'.$element)) autoload_scan_dirs($path, $list); else $list[][ROOT_PATH.$dir] = $element;
    14.     }
    15. }
    16.  
    17. function autoload($name)
    18. {
    19.     static $list = false;
    20.  
    21.     if(!$list) autoload_scan_dirs(CLASSES_DIRS, $list);
    22.  
    23.     $found = false;
    24.  
    25.     foreach($list as $class)
    26.     {
    27.         if($path = array_search($file = 'class.'.$name.'.php', $class))
    28.         {
    29.             require $path.'/'.$file;
    30.  
    31.             $found = true;
    32.         }
    33.     }
    34.  
    35.     if(!$found) trigger_error('Error. Function: autoload(). Class "'.$name.'" not found.');
    36. }
    37.  
    Всё легко перехватывается.
     
  8. neverlose

    neverlose Активный пользователь

    С нами с:
    27 авг 2008
    Сообщения:
    1.112
    Симпатии:
    20
    PHP:
    1. if($path = array_search($file = 'class.'.$name.'.php', $class))
    >>>

    PHP:
    1. if(false !== $path = array_search($file = 'class.'.$name.'.php', $class))
     
  9. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    neverlose
    Аргументируй ;)
     
  10. Krasilich

    Krasilich Активный пользователь

    С нами с:
    12 фев 2010
    Сообщения:
    14
    Симпатии:
    0
    Hight

    Да, trigger_error() таки работает. Хоть я и получаю свою ошибку и сразу после нее тот же фатал...

    Все-таки, может существуют решения с использованием исключений?
     
  11. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Krasilich
    Да какие проблемы. Бери мой автолоад и прикручивай себе. Измени в нём, что тебе надо и всё. Вместо trigger_error выводи красивое сообщение об ошибке, а потом делай die()
     
  12. Krasilich

    Krasilich Активный пользователь

    С нами с:
    12 фев 2010
    Сообщения:
    14
    Симпатии:
    0
    вот что сделал... в контексте php 5.3

    PHP:
    1.  
    2. function __autoload($classname) {
    3. //creating $path
    4. @include_once $path;
    5.  
    6. if (class_exists($classname)) {
    7.       return true;
    8. }
    9.  
    10. eval("class $classname {
    11.             function __construct() {
    12.                    throw new Exception('Class $classname not found');
    13.             }
    14.  
    15.             static function __callstatic(\$m, \$args) {
    16.                    throw new Exception('Class $classname not found');
    17.             }
    18.         }");
    19. }
     
  13. phpbidlo

    phpbidlo Активный пользователь

    С нами с:
    18 авг 2009
    Сообщения:
    49
    Симпатии:
    0
    А зачем этот eval? Просто определить класс исключения (один раз) MyFukenException и написать throw new MyFukenException('Class $classname not found');
    не позволяет религия или уровень интеллекта?
     
  14. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Кузяво - уважаю :)

    Фатальные ошибки можно еще хватать в register_shutdown_function

    при помощи http://php.net/error_get_last
     
  15. Krasilich

    Krasilich Активный пользователь

    С нами с:
    12 фев 2010
    Сообщения:
    14
    Симпатии:
    0
    phpbidlo
    Я тебе денег дам, если у тебя получиться так сделать=))
    Обрати внимание на контекст в котором все происходит.
     
  16. Krasilich

    Krasilich Активный пользователь

    С нами с:
    12 фев 2010
    Сообщения:
    14
    Симпатии:
    0
    Simpliest
    Да тут вопрос скорее не в фатале, а в том что бы бросить исключение в автолоадере...
    У самого это решение вызывает чувство дискомфорта, да и не решает проблему для php <5.3, но а что делать?=))
     
  17. phpbidlo

    phpbidlo Активный пользователь

    С нами с:
    18 авг 2009
    Сообщения:
    49
    Симпатии:
    0
    Код (Text):
    1.  
    2. <?php
    3.  
    4. class MyFuckenException extends Exception {
    5.     //...
    6. }
    7.  
    8. function __autoload($class){
    9.     $path = $class.".php";
    10.  
    11.     include_once($path);
    12.     if(!class_exists($class))
    13.         throw new MyFuckenException("$class - not exist!");
    14. }
    15.  
    16. try{
    17.     $test = new ExistedClass();
    18.  
    19.     $test1 = new NotExistedClass();
    20. }
    21. catch(MyFuckenException $e){
    22.     print "Error: ".$e->getMessage();
    23.     die();
    24. }
     
  18. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Вместо автолоада делаем Service Locator, в нем проверяем существование запрашиваемого класса, если нет - пробуем подключить файл, если после этого класс не появился - бросаем исключение.
     
  19. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
  20. Krasilich

    Krasilich Активный пользователь

    С нами с:
    12 фев 2010
    Сообщения:
    14
    Симпатии:
    0
    [vs]
    Идея, конечно здравая, но что будет если мы Service Locator'oм будем получать класс, который экстендиться от чего то??? Тут без автолоада никуда...
     
  21. phpbidlo

    phpbidlo Активный пользователь

    С нами с:
    18 авг 2009
    Сообщения:
    49
    Симпатии:
    0
    А вы внимательно? Вот его фраза
    и далее код с eval

    Про него и речь.
     
  22. phpbidlo

    phpbidlo Активный пользователь

    С нами с:
    18 авг 2009
    Сообщения:
    49
    Симпатии:
    0
    А взять автолоадер Zend и не заморачиваться - идея еще лучше!
     
  23. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Из всего контекста php 5.3 там лишь __callstatic и деньги вам предлагали не за решение в рамках php 5.3+
    так что не надо нам ля-ля.
     
  24. phpbidlo

    phpbidlo Активный пользователь

    С нами с:
    18 авг 2009
    Сообщения:
    49
    Симпатии:
    0
    Уже вам чтоли? Речь была о замене eval на непостредственный вызов throw, php 5.3 тогда вот не знаю зачем было указано.
    Если нужно нормальное рабочее решение - Zend_Loader тока так. Можете даже им деньги переслать.
     
  25. Krasilich

    Krasilich Активный пользователь

    С нами с:
    12 фев 2010
    Сообщения:
    14
    Симпатии:
    0
    К слову сказать, решение phpbidlo в моем случае даже при использовании php 5.3 не сработает, так как я не использую напрямую __autoload() (привел лишь для примера, каюсь что мог сбить с толку, хоть вначале я и описал в точности что использую я).

    Хоть, я сам, если честно, не понял в чем разница, но факт, прямой throw у меня не сработал на версии 5.3.0 в функции которая зарегистрированна spl_autoload_register().