Как заставить автозагрузчик PHP выдавать ошибку, когда в автозагружаемом файле есть ошибки времени компиляции

В моей текущей конфигурации всякий раз, когда какой-либо файл PHP содержит фатальные ошибки, такие как синтаксические ошибки или вызов несуществующей функции, я обычно получаю сообщение об ошибке, например:

Parse error: syntax error, unexpected <whatever> in /path/to/file.php on line XXX

or

Fatal error: Call to undefined function whatever() in /path/to/file.php on line YYY

или подобное в самом выводе.

Однако я использую сторонние библиотеки, которые используют сторонний автозагрузчик. Всякий раз, когда возникает фатальная ошибка в любом из автоматически загружаемых классов (включая ошибки синтаксического анализа или вызов несуществующих функций — на самом деле не совсем уверен в последнем, но определенно в случае ошибки синтаксического анализа), я просто получаю пустую страницу, и не только это: никакая ошибка не регистрируется даже в файле error_log Apache, где обычно регистрируются фатальные ошибки PHP. Таким образом, отладка становится невозможной.

Я не могу не подчеркнуть этого: это происходит только, когда фатальная ошибка возникает в каком-то автоматически загружаемом файле. В любом другом случае (включая, конечно, ошибки в файлах, включенных через require(), include() и т.п.) одни и те же ошибки отображаются в выводе и в error_log.

Я не писал код автозагрузчика, но в основном он такой:

    // no idea why this line, but I don't think it's relevant:
    ini_set('unserialize_callback_func', 'spl_autoload_call');

    spl_autoload_register(array('My_Autoloader', 'autoload'), true);

    class My_Autoloader {
        static function autoload($classname) {
            $filename = //.... computes $filename from $classname
            require_once($filename);
        }
    }

Должен быть способ заставить автозагрузчик выдавать ошибки так же, как они выдавались бы (и обрабатывались), если бы ошибки не были в автозагружаемом файле, верно?

Как мне это получить?


person matteo    schedule 14.10.2016    source источник
comment
Сделал ответ из моего комментария   -  person JustOnUnderMillions    schedule 14.10.2016
comment
Но это Fatal error: Call to undefined function whatever() не имеет ничего общего с синтаксическими ошибками.   -  person JustOnUnderMillions    schedule 14.10.2016
comment
В PHP7 большинство фатальных ошибок были преобразованы в перехватываемые исключения. trowski.com/2015/06/24/throwable -исключения-и-ошибки-в-php7   -  person Charlotte Dunois    schedule 14.10.2016
comment
Вы можете статически анализировать все файлы, чтобы исключить ошибки синтаксического анализа из командной строки, как в Unixoid (в корневом каталоге вашего кода): find -type f -exec php -l {} \; > /dev/null   -  person bishop    schedule 15.10.2016


Ответы (3)


Проверка синтаксических ошибок только в командной строке

С php -l somefile.php из PHP shell_exec('php -l /fullpath/to/somefile.php')

но вы должны проанализировать строку ответа на наличие ошибок.

Нормальный ответ No syntax errors detected in somefile.php

В PHP ‹= 5.0.4 был php.net/manual/en/function.php-check-syntax.php

Вот фатальная ошибка, которая работает:

register_shutdown_function(function(){
    $err=error_get_last();
    if($err['type']===1){
       /*you got an fatal error do something, write it to an file*/
       #file_put_contents(var_export($err,true),'myfatalerror.log');
    }
});

Надеюсь, это поможет:)

person JustOnUnderMillions    schedule 14.10.2016
comment
@matteo Смотри! - person JustOnUnderMillions; 14.10.2016
comment
Это не проверяет синтаксис файлов include()d из основного файла, для которого вы его вызываете, не так ли? - person matteo; 14.10.2016
comment
проблема в том, что файл с предполагаемой синтаксической ошибкой или фатальной ошибкой является одним из огромного количества файлов, динамически загружаемых автозагрузчиком, поэтому ручная проверка каждого из них не совсем жизнеспособна... - person matteo; 14.10.2016
comment
Нет, вы должны проверить это самостоятельно, и это возможно в автозагрузчике, прежде чем включать файл. Я должен спросить: почему в вашем приложении вообще есть файлы с синтаксическими ошибками? Почему бы не проверить их все сейчас с помощью php -l somefile.php и не исправить файлы, тогда вы избавитесь от синтаксических ошибок и сможете продолжать исправлять другие ошибки. В качестве примечания: синтаксические ошибки обнаруживаются до компиляции php-файлов, все остальные ошибки — во время выполнения. - person JustOnUnderMillions; 14.10.2016
comment
bazillion файлов с 50% синтаксических ошибок, надеюсь, за этим кодом не стоит компания. Я бы выгнал генерального директора. Или кто допустил это? - person JustOnUnderMillions; 14.10.2016
comment
Я не знаю, откуда вы взяли эти 50%. Это ОДИН файл с ошибкой, только это может быть любой из них. Да, файлы раньше работали, потом я их кучу модифицировал, где-то в одном (или в нескольких) допустил ошибку. Если бы они были включены каким-либо другим способом, кроме регистрации автозагрузчика, я бы получил сообщение об ошибке и сразу понял, где ошибка. Если на самом деле нет возможности иметь ту же обработку ошибок с автозагрузкой, которую вы получили бы с обычным включением, для меня это ошибка PHP. - person matteo; 15.10.2016
comment
В качестве примечания: синтаксические ошибки обнаруживаются до компиляции php-файлов, все остальные ошибки обнаруживаются во время выполнения: однако фатальные ошибки или, по крайней мере, некоторое подмножество фатальных ошибок, независимо от времени выполнения (с JIT концепция времени выполнения несколько нечетко) никоим образом не могут быть обнаружены в реальном времени, то есть вы не можете установить для них обработчик ошибок - это по крайней мере в 5.x, я надеюсь, что они исправили это в более поздних версиях. Я думаю, что вызов неопределенной функции является одним из таких случаев. - person matteo; 15.10.2016
comment
И, кстати, теперь я могу подтвердить, что проблема, которую я наблюдаю (т. е. фатальная ошибка не отображается и не регистрируется), ДЕЙСТВИТЕЛЬНО возникает при вызове неопределенных функций, а также с синтаксическими ошибками, поэтому php -l не поможет в этом случае. - person matteo; 15.10.2016
comment
Если вы уверены, что PHP 5.x не может выдавать фатальные ошибки (такого рода) в автозагружаемом файле так же, как и в других включенных файлах (т.е. записывать их и, если display_errors включен и в зависимости от их), пожалуйста, добавьте это к своему ответу, и я приму его, поскольку, если это так, то ответ на мой вопрос в основном состоит в том, что вы не можете этого сделать, и вы предоставляете частичное обходное решение, которое, кажется, доходит до одного можно пойти (при условии, что посылка верна) - person matteo; 15.10.2016

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

То, что ваш сторонний код вызывает такие ошибки, заставляет меня задуматься о его качестве, но пока мы проигнорируем это.

Встроенные механизмы PHP будут обрабатывать отчеты (в браузер) и журналирование (в файл). Нефатальными ошибками можно управлять с помощью вашего собственного кода после вызова set_error_handler(), однако фатальные ошибки не передаются по этому маршруту. В собственном коде можно перехватывать и обрабатывать фатальные ошибки с помощью register_shutdown_function( ). Но начните с проверки файлов журнала.

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

person symcbean    schedule 15.10.2016
comment
Единственный способ, которым код будет вести себя так, как вы предлагаете, - это если сторонний код переопределяет отчет об ошибках. Нет, это не так. - person matteo; 15.10.2016
comment
То, что ваш сторонний код вызывает такие ошибки, заставляет меня задуматься о его качестве. Может быть, я не очень ясно выразился по этому поводу: в исходном коде не было ошибок, я сам внес их при модификации. Кроме того, ошибки могут быть не обязательно в стороннем коде, они могут быть в моем собственном коде, автозагружаемом через сторонний автозагрузчик. Проблема в том, что хотя ЛЮБАЯ фатальная ошибка обычно выводится и в журнал, включая ошибки синтаксического анализа и вызовы неопределенных функций, это не происходит в автозагружаемом коде. Я начинаю думать, что это поведение PHP (ужасно неправильное). - person matteo; 15.10.2016
comment
Относительно этого: я начинаю думать, что это поведение PHP (ужасно неправильное). Я попытался настроить минимальный тестовый пример, предназначенный для воспроизведения проблемы, но это не так. Так что это вселяет в меня надежду: либо происходит что-то более тонкое, либо этот конкретный автозагрузчик на самом деле делает что-то, чего можно было бы избежать, и это приглушает ошибки. Однако я не знаю, что искать. Я искал error_reporting безрезультатно, и я не могу найти в исходном коде ничего, что явно делало бы что-то об ошибках. Любая идея, что мне нужно искать? - person matteo; 15.10.2016

Используйте исключение php, чтобы вы могли вызвать свой файл в

function inverse($x) {
    if (!$x) {
        throw new Exception('Division par zéro.');
    }
    return 1/$x;
}

try {
    echo inverse(5) . "\n";
    echo inverse(0) . "\n";
} catch (Exception $e) {
    echo 'Exception reçue : ',  $e->getMessage(), "\n";
}
person G. Mansour    schedule 14.10.2016
comment
Я не думаю, что это имеет какое-либо отношение к моему вопросу. Я говорю о фатальных ошибках, таких как синтаксические ошибки, а не об исключениях. - person matteo; 14.10.2016