(PHP 4, PHP 5, PHP 7, PHP
error_reporting — Sets which PHP errors are reported
Description
error_reporting(?int $error_level
= null
): int
Parameters
-
error_level
-
The new error_reporting
level. It takes on either a bitmask, or named constants. Using named
constants is strongly encouraged to ensure compatibility for future
versions. As error levels are added, the range of integers increases,
so older integer-based error levels will not always behave as expected.The available error level constants and the actual
meanings of these error levels are described in the
predefined constants.
Return Values
Returns the old error_reporting
level or the current level if no error_level
parameter is
given.
Changelog
Version | Description |
---|---|
8.0.0 |
error_level is nullable now.
|
Examples
Example #1 error_reporting() examples
<?php// Turn off all error reporting
error_reporting(0);// Report simple running errors
error_reporting(E_ERROR | E_WARNING | E_PARSE);// Reporting E_NOTICE can be good too (to report uninitialized
// variables or catch variable name misspellings ...)
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);// Report all errors except E_NOTICE
error_reporting(E_ALL & ~E_NOTICE);// Report all PHP errors
error_reporting(E_ALL);// Report all PHP errors
error_reporting(-1);// Same as error_reporting(E_ALL);
ini_set('error_reporting', E_ALL);?>
Notes
Tip
Passing in the value -1
will show every possible error,
even when new levels and constants are added in future PHP versions. The
behavior is equivalent to passing E_ALL
constant.
See Also
- The display_errors directive
- The html_errors directive
- The xmlrpc_errors directive
- ini_set() — Sets the value of a configuration option
info at hephoz dot de ¶
14 years ago
If you just see a blank page instead of an error reporting and you have no server access so you can't edit php configuration files like php.ini try this:
- create a new file in which you include the faulty script:
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
include("file_with_errors.php");
?>
- execute this file instead of the faulty script file
now errors of your faulty script should be reported.
this works fine with me. hope it solves your problem as well!
jcastromail at yahoo dot es ¶
2 years ago
Under PHP 8.0, error_reporting() does not return 0 when then the code uses a @ character.
For example
<?php
$a
=$array[20]; // error_reporting() returns 0 in php <8 and 4437 in PHP>=8?>
dave at davidhbrown dot us ¶
17 years ago
The example of E_ALL ^ E_NOTICE is a 'bit' confusing for those of us not wholly conversant with bitwise operators.
If you wish to remove notices from the current level, whatever that unknown level might be, use & ~ instead:
<?php
//....
$errorlevel=error_reporting();
error_reporting($errorlevel & ~E_NOTICE);
//...code that generates notices
error_reporting($errorlevel);
//...
?>
^ is the xor (bit flipping) operator and would actually turn notices *on* if they were previously off (in the error level on its left). It works in the example because E_ALL is guaranteed to have the bit for E_NOTICE set, so when ^ flips that bit, it is in fact turned off. & ~ (and not) will always turn off the bits specified by the right-hand parameter, whether or not they were on or off.
Fernando Piancastelli ¶
18 years ago
The error_reporting() function won't be effective if your display_errors directive in php.ini is set to "Off", regardless of level reporting you set. I had to set
display_errors = On
error_reporting = ~E_ALL
to keep no error reporting as default, but be able to change error reporting level in my scripts.
I'm using PHP 4.3.9 and Apache 2.0.
ecervetti at orupaca dot fr ¶
14 years ago
It could save two minutes to someone:
E_ALL & ~E_NOTICE integer value is 6135
huhiko334 at yandex dot ru ¶
4 years ago
If you get a weird mysql warnings like "Warning: mysql_query() : Your query requires a full tablescan...", don't look for error_reporting settings - it's set in php.ini.
You can turn it off with
ini_set("mysql.trace_mode","Off");
in your script
http://tinymy.link/mctct
kevinson112 at yahoo dot com ¶
5 years ago
I had the problem that if there was an error, php would just give me a blank page. Any error at all forced a blank page instead of any output whatsoever, even though I made sure that I had error_reporting set to E_ALL, display_errors turned on, etc etc. But simply running the file in a different directory allowed it to show errors!
Turns out that the error_log file in the one directory was full (2.0 Gb). I erased the file and now errors are displayed normally. It might also help to turn error logging off.
https://techysupport.co/norton-tech-support/
luisdev ¶
5 years ago
This article refers to these two reporting levels:
// Report all PHP errors (see changelog)
error_reporting(E_ALL);
// Report all PHP errors
error_reporting(-1);
What is the difference between those two levels?
Please update this article with a clear explanation of the difference and the possible use cases.
qeremy ! gmail ¶
8 years ago
If you want to see all errors in your local environment, you can set your project URL like "foo.com.local" locally and put that in bootstrap file.
<?php
if (substr($_SERVER['SERVER_NAME'], -6) == '.local') {
ini_set('display_errors', 1);
ini_set('error_reporting', E_ALL);
// or error_reporting(E_ALL);
}
?>
adam at adamhahn dot com ¶
6 years ago
To expand upon the note by chris at ocproducts dot com. If you prepend @ to error_reporting(), the function will always return 0.
<?php
error_reporting(E_ALL);
var_dump(
error_reporting(), // value of E_ALL,
@error_reporting() // value is 0
);
?>
keithm at aoeex dot com ¶
12 years ago
Some E_STRICT errors seem to be thrown during the page's compilation process. This means they cannot be disabled by dynamically altering the error level at run time within that page.
The work-around for this was to rename the file and replace the original with a error_reporting() call and then a require() call.
Ex, rename index.php to index.inc.php, then re-create index.php as:
<?php
error_reporting(E_ALL & ~(E_STRICT|E_NOTICE));
require('index.inc.php');
?>
That allows you to alter the error reporting prior to the file being compiled.
I discovered this recently when I was given code from another development firm that triggered several E_STRICT errors and I wanted to disable E_STRICT on a per-page basis.
chris at ocproducts dot com ¶
6 years ago
The error_reporting() function will return 0 if error suppression is currently active somewhere in the call tree (via the @ operator).
Rash ¶
8 years ago
If you are using the PHP development server, run from the command line via `php -S servername:port`, every single error/notice/warning will be reported in the command line itself, with file name, and line number, and stack trace.
So if you want to keep a log of all the errors even after page reloads (for help in debugging, maybe), running the PHP development server can be useful.
vdephily at bluemetrix dot com ¶
18 years ago
Note that E_NOTICE will warn you about uninitialized variables, but assigning a key/value pair counts as initialization, and will not trigger any error :
<?php
error_reporting(E_ALL);$foo = $bar; //notice : $bar uninitialized$bar['foo'] = 'hello'; // no notice, although $bar itself has never been initialized (with "$bar = array()" for example)$bar = array('foobar' => 'barfoo');
$foo = $bar['foobar'] // ok$foo = $bar['nope'] // notice : no such index
?>
&IT ¶
3 years ago
error_reporting(E_ALL);
if (!ini_get('display_errors')) {
ini_set('display_errors', '1');
}
lhenry at lhenry dot com ¶
3 years ago
In php7, what was generally a notice or a deprecated is now a warning : the same level of a mysql error … unacceptable for me.
I do have dozen of old projects and I surely d'ont want to define every variable which I eventually wrote 20y ago.
So two option: let php7 degrade my expensive SSDs writing Gb/hours or implement smthing like server level monitoring ( with auto_[pre-ap]pend_file in php.ini) and turn off E_WARNING
Custom overriding the level of php errors should be super handy and flexible …
rojaro at gmail dot com ¶
12 years ago
To enable error reporting for *ALL* error messages including every error level (including E_STRICT, E_NOTICE etc.), simply use:
<?php error_reporting(-1); ?>
j dot schriver at vindiou dot com ¶
22 years ago
error_reporting() has no effect if you have defined your own error handler with set_error_handler()
[Editor's Note: This is not quite accurate.
E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR and E_COMPILE_WARNING error levels will be handled as per the error_reporting settings.
All other levels of errors will be passed to the custom error handler defined by set_error_handler().
Zeev Suraski suggests that a simple way to use the defined levels of error reporting with your custom error handlers is to add the following line to the top of your error handling function:
if (!($type & error_reporting())) return;
-zak@php.net]
kc8yds at gmail dot com ¶
14 years ago
this is to show all errors for code that may be run on different versions
for php 5 it shows E_ALL^E_STRICT and for other versions just E_ALL
if anyone sees any problems with it please correct this post
<?php
ini_set('error_reporting', version_compare(PHP_VERSION,5,'>=') && version_compare(PHP_VERSION,6,'<') ?E_ALL^E_STRICT:E_ALL);
?>
fredrik at demomusic dot nu ¶
17 years ago
Remember that the error_reporting value is an integer, not a string ie "E_ALL & ~E_NOTICE".
This is very useful to remember when setting error_reporting levels in httpd.conf:
Use the table above or:
<?php
ini_set("error_reporting", E_YOUR_ERROR_LEVEL);
echo ini_get("error_reporting");
?>
To get the appropriate integer for your error-level. Then use:
php_admin_value error_reporting YOUR_INT
in httpd.conf
I want to share this rather straightforward tip as it is rather annoying for new php users trying to understand why things are not working when the error-level is set to (int) "E_ALL" = 0...
Maybe the PHP-developers should make ie error_reporting("E_ALL"); output a E_NOTICE informative message about the mistake?
Alex ¶
16 years ago
error_reporting() may give unexpected results if the @ error suppression directive is used.
<?php
@include 'config.php';
include 'foo.bar'; // non-existent file
?>
config.php
<?php
error_reporting(0);
?>
will throw an error level E_WARNING in relation to the non-existent file (depending of course on your configuration settings). If the suppressor is removed, this works as expected.
Alternatively using ini_set('display_errors', 0) in config.php will achieve the same result. This is contrary to the note above which says that the two instructions are equivalent.
teynon1 at gmail dot com ¶
11 years ago
It might be a good idea to include E_COMPILE_ERROR in error_reporting.
If you have a customer error handler that does not output warnings, you may get a white screen of death if a "require" fails.
Example:
<?php
error_reporting(E_ERROR | E_WARNING | E_PARSE);
function
myErrorHandler($errno, $errstr, $errfile, $errline) {
// Do something other than output message.
return true;
}$old_error_handler = set_error_handler("myErrorHandler");
require
"this file does not exist";
?>
To prevent this, simply include E_COMPILE_ERROR in the error_reporting.
<?php
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
?>
Daz Williams (The Northeast) ¶
14 years ago
Only display php errors to the developer...
<?php
if($_SERVER['REMOTE_ADDR']=="00.00.00.00")
{
ini_set('display_errors','On');
}
else
{
ini_set('display_errors','Off');
}
?>
Just replace 00.00.00.00 with your ip address.
DarkGool ¶
17 years ago
In phpinfo() error reporting level display like a bit (such as 4095)
Maybe it is a simply method to understand what a level set on your host
if you are not have access to php.ini file
<?php
$bit = ini_get('error_reporting');
while ($bit > 0) {
for($i = 0, $n = 0; $i <= $bit; $i = 1 * pow(2, $n), $n++) {
$end = $i;
}
$res[] = $end;
$bit = $bit - $end;
}
?>
In $res you will have all constants of error reporting
$res[]=int(16) // E_CORE_ERROR
$res[]=int(8) // E_NOTICE
...
misplacedme at gmail dot com ¶
14 years ago
I always code with E_ALL set.
After a couple of pages of
<?php
$username = (isset($_POST['username']) && !empty($_POST['username']))....
?>
I made this function to make things a little bit quicker. Unset values passed by reference won't trigger a notice.
<?php
function test_ref(&$var,$test_function='',$negate=false) {
$stat = true;
if(!isset($var)) $stat = false;
if (!empty($test_function) && function_exists($test_function)){
$stat = $test_function($var);
$stat = ($negate) ? $stat^1 : $stat;
}
elseif($test_function == 'empty') {
$stat = empty($var);
$stat = ($negate) ? $stat^1 : $stat;
}
elseif (!function_exists($test_function)) {
$stat = false;
trigger_error("$test_function() is not a valid function");
}
$stat = ($stat) ? true : false;
return $stat;
}
$a = '';
$b = '15';test_ref($a,'empty',true); //False
test_ref($a,'is_int'); //False
test_ref($a,'is_numeric'); //False
test_ref($b,'empty',true); //true
test_ref($b,'is_int'); //False
test_ref($b,'is_numeric'); //false
test_ref($unset,'is_numeric'); //false
test_ref($b,'is_number'); //returns false, with an error.
?>
forcemdt ¶
9 years ago
Php >5.4
Creating a Custom Error Handler
set_error_handler("customError",E_ALL);
function customError($errno, $errstr)
{
echo "<b>Error:</b> [$errno] $errstr<br>";
echo "Ending Script";
die();
}
Антон Шевчук // Web-разработчик
Не совершает ошибок только тот, кто ничего не делает, и мы тому пример – трудимся не покладая рук над созданием рабочих мест для тестировщиков
О да, в этой статье я поведу свой рассказа об ошибках в PHP, и том как их обуздать.
Ошибки
Разновидности в семействе ошибок
Перед тем как приручать ошибки, я бы рекомендовал изучить каждый вид и отдельно обратить внимание на самых ярких представителей.
Чтобы ни одна ошибка не ушла незамеченной потребуется включить отслеживание всех ошибок с помощью функции error_reporting(), а с помощью директивы display_errors включить их отображение:
<?php error_reporting(E_ALL); ini_set('display_errors', 1);
Фатальные ошибки
Самый грозный вид ошибок – фатальные, они могут возникнуть как при компиляции, так и при работе парсера или PHP-скрипта, выполнение скрипта при этом прерывается.
E_PARSE
Это ошибка появляется, когда вы допускаете грубую ошибку синтаксиса и интерпретатор PHP не понимает, что вы от него хотите, например если не закрыли фигурную или круглую скобочку:
<?php /** Parse error: syntax error, unexpected end of file */ {
Или написали на непонятном языке:
<?php /** Parse error: syntax error, unexpected '...' (T_STRING) */ Тут будет ошибка парсера
Лишние скобочки тоже встречаются, и не важно круглые либо фигурные:
<?php /** Parse error: syntax error, unexpected '}' */ }
Отмечу один важный момент – код файла, в котором вы допустили parse error не будет выполнен, следовательно, если вы попытаетесь включить отображение ошибок в том же файле, где возникла ошибка парсера то это не сработает:
<?php // этот код не сработает error_reporting(E_ALL); ini_set('display_errors', 1); // т.к. вот тут ошибка парсера
E_ERROR
Это ошибка появляется, когда PHP понял что вы хотите, но сделать сие не получилось ввиду ряда причин, так же прерывает выполнение скрипта, при этом код до появления ошибки сработает:
Не был найден подключаемый файл:
/** Fatal error: require_once(): Failed opening required 'not-exists.php' (include_path='.:/usr/share/php:/usr/share/pear') */ require_once 'not-exists.php';
Было брошено исключение (что это за зверь, расскажу немного погодя), но не было обработано:
/** Fatal error: Uncaught exception 'Exception' */ throw new Exception();
При попытке вызвать несуществующий метод класса:
/** Fatal error: Call to undefined method stdClass::notExists() */ $stdClass = new stdClass(); $stdClass->notExists();
Отсутствия свободной памяти (больше, чем прописано в директиве memory_limit) или ещё чего-нить подобного:
/** Fatal Error: Allowed Memory Size */ $arr = array(); while (true) { $arr[] = str_pad(' ', 1024); }
Очень часто происходит при чтении либо загрузки больших файлов, так что будьте внимательны с вопросом потребляемой памяти
Рекурсивный вызов функции. В данном примере он закончился на 256-ой итерации, ибо так прописано в настройках xdebug:
/** Fatal error: Maximum function nesting level of '256' reached, aborting! */ function deep() { deep(); } deep();
Не фатальные
Данный вид не прерывает выполнение скрипта, но именно их обычно находит тестировщик, и именно они доставляют больше всего хлопот у начинающих разработчиков.
E_WARNING
Частенько встречается, когда подключаешь файл с использованием include
, а его не оказывается на сервере или ошиблись указывая путь к файлу:
/** Warning: include_once(): Failed opening 'not-exists.php' for inclusion */ include_once 'not-exists.php';
Бывает, если используешь неправильный тип аргументов при вызове функций:
/** Warning: join(): Invalid arguments passed */ join('string', 'string');
Их очень много, и перечислять все не имеет смысла…
E_NOTICE
Это самые распространенные ошибки, мало того, есть любители отключать вывод ошибок и клепают их целыми днями. Возникают при целом ряде тривиальных ошибок.
Когда обращаются к неопределенной переменной:
/** Notice: Undefined variable: a */ echo $a;
Когда обращаются к несуществующему элементу массива:
<?php /** Notice: Undefined index: a */ $b = array(); $b['a'];
Когда обращаются к несуществующей константе:
/** Notice: Use of undefined constant UNKNOWN_CONSTANT - assumed 'UNKNOWN_CONSTANT' */ echo UNKNOWN_CONSTANT;
Когда не конвертируют типы данных:
/** Notice: Array to string conversion */ echo array();
Для избежания подобных ошибок – будьте внимательней, и если вам IDE подсказывает о чём-то – не игнорируйте её:
E_STRICT
Это ошибки, которые научат вас писать код правильно, чтобы не было стыдно, тем более IDE вам эти ошибки сразу показывают. Вот например, если вызвали не статический метод как статику, то код будет работать, но это как-то неправильно, и возможно появление серьёзных ошибок, если в дальнейшем метод класса будет изменён, и появится обращение к $this
:
/** Strict standards: Non-static method Strict::test() should not be called statically */ class Strict { public function test() { echo 'Test'; } } Strict::test();
E_DEPRECATED
Так PHP будет ругаться, если вы используете устаревшие функции (т.е. те, что помечены как deprecated, и в следующем мажорном релизе их не будет):
/** Deprecated: Function split() is deprecated */ // популярная функция, всё никак не удалят из PHP // deprecated since 5.3 split(',', 'a,b');
В моём редакторе подобные функции будут зачёркнуты:
Обрабатываемые
Этот вид, которые разводит сам разработчик кода, я их уже давно не встречал, не рекомендую их вам заводить:
E_USER_ERROR
– критическая ошибкаE_USER_WARNING
– не критическая ошибкаE_USER_NOTICE
– сообщения которые не являются ошибками
Отдельно стоит отметить E_USER_DEPRECATED
– этот вид всё ещё используется очень часто для того, чтобы напомнить программисту, что метод или функция устарели и пора переписать код без использования оной. Для создания этой и подобных ошибок используется функция trigger_error():
/** * @deprecated Deprecated since version 1.2, to be removed in 2.0 */ function generateToken() { trigger_error('Function `generateToken` is deprecated, use class `Token` instead', E_USER_DEPRECATED); // ... // code ... // ... }
Теперь, когда вы познакомились с большинством видов и типов ошибок, пора озвучить небольшое пояснение по работе директивы
display_errors
:
- если
display_errors = on
, то в случае ошибки браузер получит html c текстом ошибки и кодом 200- если же
display_errors = off
, то для фатальных ошибок код ответа будет 500 и результат не будет возвращён пользователю, для остальных ошибок – код будет работать неправильно, но никому об этом не расскажет
Приручение
Для работы с ошибками в PHP существует 3 функции:
- set_error_handler() — устанавливает обработчик для ошибок, которые не обрывают работу скрипта (т.е. для не фатальных ошибок)
- error_get_last() — получает информацию о последней ошибке
- register_shutdown_function() — регистрирует обработчик который будет запущен при завершении работы скрипта. Данная функция не относится непосредственно к обработчикам ошибок, но зачастую используется именно для этого
Теперь немного подробностей об обработке ошибок с использованием set_error_handler()
, в качестве аргументов данная функция принимает имя функции, на которую будет возложена миссия по обработке ошибок и типы ошибок которые будут отслеживаться. Обработчиком ошибок может так же быть методом класса, или анонимной функцией, главное, чтобы он принимал следующий список аргументов:
$errno
– первый аргумент содержит тип ошибки в виде целого числа$errstr
– второй аргумент содержит сообщение об ошибке$errfile
– необязательный третий аргумент содержит имя файла, в котором произошла ошибка$errline
– необязательный четвертый аргумент содержит номер строки, в которой произошла ошибка$errcontext
– необязательный пятый аргумент содержит массив всех переменных, существующих в области видимости, где произошла ошибка
В случае если обработчик вернул true
, то ошибка будет считаться обработанной и выполнение скрипта продолжится, иначе — будет вызван стандартный обработчик, который логирует ошибку и в зависимости от её типа продолжит выполнение скрипта или завершит его. Вот пример обработчика:
<?php // включаем отображение всех ошибок, кроме E_NOTICE error_reporting(E_ALL & ~E_NOTICE); ini_set('display_errors', 1); // наш обработчик ошибок function myHandler($level, $message, $file, $line, $context) { // в зависимости от типа ошибки формируем заголовок сообщения switch ($level) { case E_WARNING: $type = 'Warning'; break; case E_NOTICE: $type = 'Notice'; break; default; // это не E_WARNING и не E_NOTICE // значит мы прекращаем обработку ошибки // далее обработка ложится на сам PHP return false; } // выводим текст ошибки echo "<h2>$type: $message</h2>"; echo "<p><strong>File</strong>: $file:$line</p>"; echo "<p><strong>Context</strong>: $". join(', $', array_keys($context))."</p>"; // сообщаем, что мы обработали ошибку, и дальнейшая обработка не требуется return true; } // регистрируем наш обработчик, он будет срабатывать на для всех типов ошибок set_error_handler('myHandler', E_ALL);
У вас не получится назначить более одной функции для обработки ошибок, хотя очень бы хотелось регистрировать для каждого типа ошибок свой обработчик, но нет – пишите один обработчик, и всю логику отображения для каждого типа описывайте уже непосредственно в нём
С обработчиком, который написан выше есть одна существенная проблема – он не ловит фатальные ошибки, и вместо сайта пользователи увидят лишь пустую страницу, либо, что ещё хуже, сообщение об ошибке. Дабы не допустить подобного сценария следует воспользоваться функцией register_shutdown_function() и с её помощью зарегистрировать функцию, которая всегда будет выполняться по окончанию работы скрипта:
function shutdown() { echo 'Этот текст будет всегда отображаться'; } register_shutdown_function('shutdown');
Данная функция будет срабатывать всегда!
Но вернёмся к ошибкам, для отслеживания появления в коде ошибки воспользуемся функцией error_get_last(), с её помощью можно получить информацию о последней выявленной ошибке, а поскольку фатальные ошибки прерывают выполнение кода, то они всегда будут выполнять роль “последних”:
function shutdown() { $error = error_get_last(); if ( // если в коде была допущена ошибка is_array($error) && // и это одна из фатальных ошибок in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR]) ) { // очищаем буфер вывода (о нём мы ещё поговорим в последующих статьях) while (ob_get_level()) { ob_end_clean(); } // выводим описание проблемы echo 'Сервер находится на техническом обслуживании, зайдите позже'; } } register_shutdown_function('shutdown');
Задание
Дополнить обработчик фатальных ошибок выводом исходного кода файла где была допущена ошибка, а так же добавьте подсветку синтаксиса выводимого кода.
О прожорливости
Проведём простой тест, и выясним – сколько драгоценных ресурсов кушает самая тривиальная ошибка:
/** * Этот код не вызывает ошибок */ // сохраняем параметры памяти и времени выполнения скрипта $memory = memory_get_usage(); $time= microtime(true); $a = ''; $arr = []; for ($i = 0; $i < 10000; $i++) { $arr[$a] = $i; } printf('%f seconds <br/>', microtime(true) - $time); echo number_format(memory_get_usage() - $memory, 0, '.', ' '), ' bytes<br/>';
В результате запуска данного скрипта у меня получился вот такой результат:
0.002867 seconds 984 bytes
Теперь добавим ошибку в цикле:
/** * Этот код содержит ошибку */ // сохраняем параметры памяти и времени выполнения скрипта $memory = memory_get_usage(); $time= microtime(true); $a = ''; $arr = []; for ($i = 0; $i < 10000; $i++) { $arr[$b] = $i; // тут ошиблись с именем переменной } printf('%f seconds <br/>', microtime(true) - $time); echo number_format(memory_get_usage() - $memory, 0, '.', ' '), ' bytes<br/>';
Результат ожидаемо хуже, и на порядок (даже на два порядка!):
0.263645 seconds 992 bytes
Вывод однозначен – ошибки в коде приводят к лишней прожорливости скриптов – так что во время разработки и тестирования приложения включайте отображение всех ошибок!
Тестирование проводил на PHP версии 5.6, в седьмой версии результат лучше – 0.0004 секунды против 0.0050 – разница только на один порядок, но в любом случае результат стоит прикладываемых усилий по исправлению ошибок
Где собака зарыта
В PHP есть спец символ «@» – оператор подавления ошибок, его используют дабы не писать обработку ошибок, а положится на корректное поведение PHP в случае чего:
<?php echo @UNKNOWN_CONSTANT;
При этом обработчик ошибок указанный в set_error_handler()
всё равно будет вызван, а факт того, что к ошибке было применено подавление можно отследить вызвав функцию error_reporting()
внутри обработчика, в этом случае она вернёт 0
.
Если вы в такой способ подавляете ошибки, то это уменьшает нагрузку на процессор в сравнении с тем, если вы их просто скрываете (см. сравнительный тест выше), но в любом случае, подавление ошибок это зло
Исключения
В эру PHP4 не было исключений (exceptions), всё было намного сложнее, и разработчики боролись с ошибками как могли, это было сражение не на жизнь, а на смерть… Окунуться в эту увлекательную историю противостояния можете в статье Исключительный код. Часть 1. Стоит ли её читать сейчас? Думаю да, ведь это поможет вам понять эволюцию языка, и раскроет всю прелесть исключений
Исключения — исключительные событие в PHP, в отличии от ошибок не просто констатируют наличие проблемы, а требуют от программиста дополнительных действий по обработке каждого конкретного случая.
К примеру, скрипт должен сохранить какие-то данные в кеш файл, если что-то пошло не так (нет доступа на запись, нет места на диске), генерируется исключение соответствующего типа, а в обработчике исключений принимается решение – сохранить в другое место или сообщить пользователю о проблеме.
Исключение – это объект который наследуется от класса Exception
, содержит текст ошибки, статус, а также может содержать ссылку на другое исключение которое стало первопричиной данного. Модель исключений в PHP схожа с используемыми в других языках программирования. Исключение можно инициировать (как говорят, “бросить”) при помощи оператора throw
, и можно перехватить (“поймать”) оператором catch
. Код генерирующий исключение, должен быть окружен блоком try
, для того чтобы можно было перехватить исключение. Каждый блок try
должен иметь как минимум один соответствующий ему блок catch
или finally
:
try { // код который может выбросить исключение if (rand(0, 1)) { throw new Exception('One') } else { echo 'Zero'; } } catch (Exception $e) { // код который может обработать исключение echo $e->getMessage(); }
В каких случаях стоит применять исключения:
- если в рамках одного метода/функции происходит несколько операций которые могут завершиться неудачей
- если используемый вами фреймверк или библиотека декларируют их использование
Для иллюстрации первого сценария возьмём уже озвученный пример функции для записи данных в файл – помешать нам может очень много факторов, а для того, чтобы сообщить выше стоящему коду в чем именно была проблема необходимо создать и выбросить исключение:
$directory = __DIR__ . DIRECTORY_SEPARATOR . 'logs'; // директории может не быть if (!is_dir($directory)) { throw new Exception('Directory `logs` is not exists'); } // может не быть прав на запись в директорию if (!is_writable($directory)) { throw new Exception('Directory `logs` is not writable'); } // возможно кто-то уже создал файл, и закрыл к нему доступ if (!$file = @fopen($directory . DIRECTORY_SEPARATOR . date('Y-m-d') . '.log', 'a+')) { throw new Exception('System can't create log file'); } fputs($file, date('[H:i:s]') . " donen"); fclose($file);
Соответственно ловить данные исключения будем примерно так:
try { // код который пишет в файл // ... } catch (Exception $e) { // выводим текст ошибки echo 'Не получилось: '. $e->getMessage(); }
В данном примере приведен очень простой сценарий обработки исключений, когда у нас любая исключительная ситуация обрабатывается на один манер. Но зачастую – различные исключения требуют различного подхода к обработке, и тогда следует использовать коды исключений и задать иерархию исключений в приложении:
// исключения файловой системы class FileSystemException extends Exception {} // исключения связанные с директориями class DirectoryException extends FileSystemException { // коды исключений const DIRECTORY_NOT_EXISTS = 1; const DIRECTORY_NOT_WRITABLE = 2; } // исключения связанные с файлами class FileException extends FileSystemException {}
Теперь, если использовать эти исключения то можно получить следующий код:
try { // код который пишет в файл if (!is_dir($directory)) { throw new DirectoryException('Directory `logs` is not exists', DirectoryException::DIRECTORY_NOT_EXISTS); } if (!is_writable($directory)) { throw new DirectoryException('Directory `logs` is not writable', DirectoryException::DIRECTORY_NOT_WRITABLE); } if (!$file = @fopen($directory . DIRECTORY_SEPARATOR . date('Y-m-d') . '.log', 'a+')) { throw new FileException('System can't open log file'); } fputs($file, date('[H:i:s]'') . " donen"); fclose($file); } catch (DirectoryException $e) { echo 'С директорией возникла проблема: '. $e->getMessage(); } catch (FileException $e) { echo 'С файлом возникла проблема: '. $e->getMessage(); } catch (FileSystemException $e) { echo 'Ошибка файловой системы: '. $e->getMessage(); } catch (Exception $e) { echo 'Ошибка сервера: '. $e->getMessage(); }
Важно помнить, что Exception — это прежде всего исключительное событие, иными словами исключение из правил. Не нужно использовать их для обработки очевидных ошибок, к примеру, для валидации введённых пользователем данных (хотя тут не всё так однозначно). При этом обработчик исключений должен быть написан в том месте, где он будет способен его обработать. К примеру, обработчик для исключений вызванных недоступностью файла для записи должен быть в методе, который отвечает за выбор файла или методе его вызывающем, для того что бы он имел возможность выбрать другой файл или другую директорию.
Так, а что будет если не поймать исключение? Вы получите “Fatal Error: Uncaught exception …”. Неприятно.
Чтобы избежать подобной ситуации следует использовать функцию set_exception_handler() и установить обработчик для исключений, которые брошены вне блока try-catch и не были обработаны. После вызова такого обработчика выполнение скрипта будет остановлено:
// в качестве обработчика событий // будем использовать анонимную функцию set_exception_handler(function($exception) { /** @var Exception $exception */ echo $exception->getMessage(), "<br/>n"; echo $exception->getFile(), ':', $exception->getLine(), "<br/>n"; echo $exception->getTraceAsString(), "<br/>n"; });
Ещё расскажу про конструкцию с использованием блока finally
– этот блок будет выполнен вне зависимости от того, было выброшено исключение или нет:
try { // код который может выбросить исключение } catch (Exception $e) { // код который может обработать исключение // если конечно оно появится } finally { // код, который будет выполнен при любом раскладе }
Для понимания того, что это нам даёт приведу следующий пример использования блока finally
:
try { // где-то глубоко внутри кода // соединение с базой данных $handler = mysqli_connect('localhost', 'root', '', 'test'); try { // при работе с БД возникла исключительная ситуация // ... throw new Exception('DB error'); } catch (Exception $e) { // исключение поймали, обработали на своём уровне // и должны его пробросить вверх, для дальнейшей обработки throw new Exception('Catch exception', 0, $e); } finally { // но, соединение с БД необходимо закрыть // будем делать это в блоке finally mysqli_close($handler); } // этот код не будет выполнен, если произойдёт исключение в коде выше echo "Ok"; } catch (Exception $e) { // ловим исключение, и выводим текст echo $e->getMessage(); echo "<br/>"; // выводим информацию о первоначальном исключении echo $e->getPrevious()->getMessage(); }
Т.е. запомните – блок finally
будет выполнен даже в том случае, если вы в блоке catch
пробрасываете исключение выше (собственно именно так он и задумывался).
Для вводной статьи информации в самый раз, кто жаждет ещё подробностей, то вы их найдёте в статье Исключительный код
Задание
Написать свой обработчик исключений, с выводом текста файла где произошла ошибка, и всё это с подсветкой синтаксиса, так же не забудьте вывести trace в читаемом виде. Для ориентира – посмотрите как это круто выглядит у whoops.
PHP7 – всё не так, как было раньше
Так, вот вы сейчас всю информацию выше усвоили и теперь я буду грузить вас нововведениями в PHP7, т.е. я буду рассказывать о том, с чем вы столкнётесь через год работы PHP разработчиком. Ранее я вам рассказывал и показывал на примерах какой костыль нужно соорудить, чтобы отлавливать критические ошибки, так вот – в PHP7 это решили исправить, но как обычно завязались на обратную совместимость кода, и получили хоть и универсальное решение, но оно далеко от идеала. А теперь по пунктам об изменениях:
- при возникновении фатальных ошибок типа
E_ERROR
или фатальных ошибок с возможностью обработкиE_RECOVERABLE_ERROR
PHP выбрасывает исключение - эти исключения не наследуют класс Exception (помните я говорил об обратной совместимости, это всё ради неё)
- эти исключения наследуют класс Error
- оба класса Exception и Error реализуют интерфейс Throwable
- вы не можете реализовать интерфейс Throwable в своём коде
Интерфейс Throwable
практически полностью повторяет нам Exception
:
interface Throwable { public function getMessage(): string; public function getCode(): int; public function getFile(): string; public function getLine(): int; public function getTrace(): array; public function getTraceAsString(): string; public function getPrevious(): Throwable; public function __toString(): string; }
Сложно? Теперь на примерах, возьмём те, что были выше и слегка модернизируем:
try { // файл, который вызывает ошибку парсера include 'e_parse_include.php'; } catch (Error $e) { var_dump($e); }
В результате ошибку поймаем и выведем:
object(ParseError)#1 (7) { ["message":protected] => string(48) "syntax error, unexpected 'будет' (T_STRING)" ["string":"Error":private] => string(0) "" ["code":protected] => int(0) ["file":protected] => string(49) "/www/education/error/e_parse_include.php" ["line":protected] => int(4) ["trace":"Error":private] => array(0) { } ["previous":"Error":private] => NULL }
Как видите – поймали исключение ParseError, которое является наследником исключения Error
, который реализует интерфейс Throwable
, в доме который построил Джек. Ещё есть другие, но не буду мучать – для наглядности приведу иерархию исключений:
interface Throwable |- Exception implements Throwable | |- ErrorException extends Exception | |- ... extends Exception | `- ... extends Exception `- Error implements Throwable |- TypeError extends Error |- ParseError extends Error |- ArithmeticError extends Error | `- DivisionByZeroError extends ArithmeticError `- AssertionError extends Error
TypeError – для ошибок, когда тип аргументов функции не совпадает с передаваемым типом:
try { (function(int $one, int $two) { return; })('one', 'two'); } catch (TypeError $e) { echo $e->getMessage(); }
ArithmeticError – могут возникнуть при математических операциях, к примеру когда результат вычисления превышает лимит выделенный для целого числа:
try { 1 << -1; } catch (ArithmeticError $e) { echo $e->getMessage(); }
DivisionByZeroError – ошибка деления на ноль:
try { 1 / 0; } catch (ArithmeticError $e) { echo $e->getMessage(); }
AssertionError – редкий зверь, появляется когда условие заданное в assert() не выполняется:
ini_set('zend.assertions', 1); ini_set('assert.exception', 1); try { assert(1 === 0); } catch (AssertionError $e) { echo $e->getMessage(); }
При настройках production-серверов, директивы
zend.assertions
иassert.exception
отключают, и это правильно
Задание
Написать универсальный обработчик ошибок для PHP7, который будет отлавливать все возможные исключения.
При написании данного раздела были использованы материалы из статьи Throwable Exceptions and Errors in PHP 7
Отладка
Иногда для отладки кода нужно отследить что происходило с переменной или объектом на определённом этапе, для этих целей есть функция debug_backtrace() и debug_print_backtrace() которые вернут историю вызовов функций/методов в обратном порядке:
<?php function example() { echo '<pre>'; debug_print_backtrace(); echo '</pre>'; } class ExampleClass { public static function method () { example(); } } ExampleClass::method();
В результате выполнения функции debug_print_backtrace()
будет выведен список вызовов приведших нас к данной точке:
#0 example() called at [/www/education/error/backtrace.php:10] #1 ExampleClass::method() called at [/www/education/error/backtrace.php:14]
Проверить код на наличие синтаксических ошибок можно с помощью функции php_check_syntax() или же команды php -l [путь к файлу]
, но я не встречал использования оных.
Assert
Отдельно хочу рассказать о таком экзотическом звере как assert() в PHP, собственно это кусочек контрактной методологии программирования, и дальше я расскажу вам как я никогда его не использовал
Первый случай – это когда вам надо написать TODO прямо в коде, да так, чтобы точно не забыть реализовать заданный функционал:
// включаем вывод ошибок error_reporting(E_ALL); ini_set('display_errors', 1); // включаем asserts ini_set('zend.assertions', 1); ini_set('assert.active', 1); assert(false, "Remove it!");
В результате выполнения данного кода получим E_WARNING
:
Warning: assert(): Remove it! failed
PHP7 можно переключить в режим exception, и вместо ошибки будет всегда появляться исключение AssertionError
:
// включаем asserts ini_set('zend.assertions', 1); ini_set('assert.active', 1); // переключаем на исключения ini_set('assert.exception', 1); assert(false, "Remove it!");
В результате ожидаемо получаем не пойманный AssertionError
. При необходимости, можно выбрасывать произвольное исключение:
assert(false, new Exception("Remove it!"));
Но я бы рекомендовал использовать метки
@TODO
, современные IDE отлично с ними работают, и вам не нужно будет прикладывать дополнительные усилия и ресурсы для работы с ними
Второй вариант использования – это создание некоего подобия TDD, но помните – это лишь подобие. Хотя, если сильно постараться, то можно получить забавный результат, который поможет в тестировании вашего кода:
// callback-функция для вывода информации в браузер function backlog($script, $line, $code, $message) { echo "<h3>$message</h3>"; highlight_string ($code); } // устанавливаем callback-функцию assert_options(ASSERT_CALLBACK, 'backlog'); // отключаем вывод предупреждений assert_options(ASSERT_WARNING, false); // пишем проверку и её описание assert("sqr(4) == 16", "When I send integer, function should return square of it"); // функция, которую проверяем function sqr($a) { return; // она не работает }
Третий теоретический вариант – это непосредственно контрактное программирование – когда вы описали правила использования своей библиотеки, но хотите точно убедится, что вас поняли правильно, и в случае чего сразу указать разработчику на ошибку (я вот даже не уверен, что правильно его понимаю, но пример кода вполне рабочий):
/** * Настройки соединения должны передаваться в следующем виде * * [ * 'host' => 'localhost', * 'port' => 3306, * 'name' => 'dbname', * 'user' => 'root', * 'pass' => '' * ] * * @param $settings */ function setupDb ($settings) { // проверяем настройки assert(isset($settings['host']), 'Db `host` is required'); assert(isset($settings['port']) && is_int($settings['port']), 'Db `port` is required, should be integer'); assert(isset($settings['name']), 'Db `name` is required, should be integer'); // соединяем с БД // ... } setupDb(['host' => 'localhost']);
Никогда не используйте
assert()
для проверки входных параметров, ведь фактическиassert()
интерпретирует строковую переменную (ведёт себя какeval()
), а это чревато PHP-инъекцией. И да, это правильное поведение, т.к. просто отключив assert’ы всё что передаётся внутрь будет проигнорировано, а если делать как в примере выше, то код будет выполняться, а внутрь отключенного assert’a будет передан булевый результат выполнения
Если у вас есть живой опыт использования assert()
– поделитесь со мной, буду благодарен. И да, вот вам ещё занимательно чтива по этой теме – PHP Assertions, с таким же вопросом в конце
В заключение
Я за вас напишу выводы из данной статьи:
- Ошибкам бой – их не должно быть в вашем коде
- Используйте исключения – работу с ними нужно правильно организовать и будет счастье
- Assert – узнали о них, и хорошо
P.S. Спасибо Максиму Слесаренко за помощь в написании статьи
Время на прочтение
6 мин
Количество просмотров 66K
В статье представлена очередная попытка разобраться с ошибками, которые могут встретиться на вашем пути php-разработчика, их возможная классификация, примеры их возникновения, влияние ошибок на ответ клиенту, а также инструкции по написанию своего обработчика ошибок.
Статья разбита на четыре раздела:
- Классификация ошибок.
- Пример, демонстрирующий различные виды ошибок и его поведение при различных настройках.
- Написание собственного обработчика ошибок.
- Полезные ссылки.
Классификация ошибок
Все ошибки, условно, можно разбить на категории по нескольким критериям.
Фатальность:
- Фатальные
Неустранимые ошибки. Работа скрипта прекращается.
E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR. - Не фатальные
Устранимые ошибки. Работа скрипта не прекращается.
E_WARNING, E_NOTICE, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNING, E_USER_NOTICE, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED. - Смешанные
Фатальные, но только, если не обработаны функцией, определенной пользователем в set_error_handler().
E_USER_ERROR, E_RECOVERABLE_ERROR.
Возможность перехвата ошибки функцией, определенной в set_error_handler():
- Перехватываемые (не фатальные и смешанные)
E_USER_ERROR, E_RECOVERABLE_ERROR, E_WARNING, E_NOTICE, E_USER_WARNING, E_USER_NOTICE, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED. - Не перехватываемые (фатальные)
E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING.
Инициатор:
- Инициированы пользователем
E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE. - Инициированы PHP
E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_WARNING, E_NOTICE, E_CORE_WARNING, E_COMPILE_WARNING, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED, E_USER_ERROR, E_RECOVERABLE_ERROR.
Для нас, в рамках данной статьи, наиболее интересны классификации по первым двум критериям, о чем будет рассказано далее.
Примеры возникновения ошибок
Листинг index.php
<?php
// определеяем уровень протоколирования ошибок
error_reporting(E_ALL | E_STRICT);
// определяем режим вывода ошибок
ini_set('display_errors', 'On');
// подключаем файл с ошибками
require 'errors.php';
Листинг errors.php
<?php
echo "Файл с ошибками. Начало<br>";
/*
* перехватываемые ошибки (ловятся функцией set_error_handler())
*/
// NONFATAL - E_NOTICE
// echo $undefined_var;
// NONFATAL - E_WARNING
// array_key_exists('key', NULL);
// NONFATAL - E_DEPRECATED
split('[/.-]', "12/21/2012"); // split() deprecated начиная с php 5.3.0
// NONFATAL - E_STRICT
// class c {function f(){}} c::f();
// NONFATAL - E_USER_DEPRECATED
// trigger_error("E_USER_DEPRECATED", E_USER_DEPRECATED);
// NONFATAL - E_USER_WARNING
// trigger_error("E_USER_WARNING", E_USER_WARNING);
// NONFATAL - E_USER_NOTICE
// trigger_error("E_USER_NOTICE", E_USER_NOTICE);
// FATAL, если не обработана функцией set_error_handler - E_RECOVERABLE_ERROR
// class b {function f(int $a){}} $b = new b; $b->f(NULL);
// FATAL, если не обработана функцией set_error_handler - E_USER_ERROR
// trigger_error("E_USER_ERROR", E_USER_ERROR);
/*
* неперехватываемые (не ловятся функцией set_error_handler())
*/
// FATAL - E_ERROR
// undefined_function();
// FATAL - E_PARSE
// parse_error
// FATAL - E_COMPILE_ERROR
// $var[];
echo "Файл с ошибками. Конец<br>";
Примечание: для полной работоспособности скрипта необходим PHP версии не ниже 5.3.0.
В файле errors.php представлены выражения, инициирующие практически все возможные ошибки. Исключение составили: E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_WARNING, генерируемые ядром Zend. В теории, встретить их в реальной работе вы не должны.
В следующей таблице приведены варианты поведения этого скрипта в различных условиях (в зависимости от значений директив display_errors и error_reporting):
Группа ошибок | Значения директив* | Статус ответа сервера | Ответ клиенту** |
---|---|---|---|
E_PARSE, E_COMPILE_ERROR*** | display_errors = off error_reporting = ANY |
500 | Пустое значение |
display_errors = on error_reporting = ANY |
200 | Сообщение об ошибке | |
E_USER_ERROR, E_ERROR, E_RECOVERABLE_ERROR | display_errors = off error_reporting = ANY |
500 | Вывод скрипта до ошибки |
display_errors = on error_reporting = ANY |
200 | Сообщение об ошибке и вывод скрипта до ошибки | |
Не фатальные ошибки | display_errors = off error_reporting = ANY и display_errors = on error_reporting = 0 |
200 | Весь вывод скрипта |
display_errors = on error_reporting = E_ALL | E_STRICT |
200 | Сообщение об ошибке и весь вывод скрипта |
* Значение ANY означает E_ALL | E_STRICT или 0.
** Ответ клиенту может отличаться от ответов на реальных скриптах. Например, вывод какой-либо информации до включения файла errors.php, будет фигурировать во всех рассмотренных случаях.
*** Если в файле errors.php заменить пример для ошибки E_COMPILE_ERROR на require "missing_file.php";
, то ошибка попадет во вторую группу.
Значение, приведенной выше, таблицы можно описать следующим образом:
- Наличие в файле скрипта ошибки, приводящей его в «негодное» состояние (невозможность корректно обработать), на выходе даст пустое значение или же только само сообщение об ошибке, в зависимости от значения директивы display_errors.
- Скрипт в файле с фатальной ошибкой, не относящейся к первому пункту, будет выполняться в штатном режиме до самой ошибки.
- Наличие в файле фатальной ошибки при display_errors = Off обозначит 500 статус ответа.
- Не фатальные ошибки, как и следовало ожидать, в контексте возможности исполнения скрипта в целом, на работоспособность не повлияют.
Собственный обработчик ошибок
Для написания собственного обработчика ошибок необходимо знать, что:
- для получения информации о последней произошедшей ошибке существует функция error_get_last();
- для определения собственного обработчика ошибок существует функция set_error_handler(), но фатальные ошибки нельзя «перехватить» этой функцией;
- используя register_shutdown_function(), можно зарегистрировать свою функцию, выполняемую по завершении работы скрипта, и в ней, используя знания из первого пункта, если фатальная ошибка имела место быть, предпринять необходимые действия;
- сообщение о фатальной ошибке в любом случае попадет в буфер вывода;
- воспользовавшись функциями контроля вывода можно предотвратить отображение нежелательной информации;
- при использовании оператора управления ошибками (знак @) функция, определенная в set_error_handler() все равно будет вызвана, но функция error_reporting() в этом случае вернет 0, чем и можно пользоваться для прекращения работы или определения другого поведения своего обработчика ошибок.
Третий пункт поясню: зарегистрированная нами функция при помощи register_shutdown_function() выполнится в любом случае — корректно ли завершился скрипт, либо же был прерван в связи с критичной (фатальной) ошибкой. Второй вариант мы можем однозначно определить, воспользовавшись информацией предоставленной функцией error_get_last(), и, если ошибка все же была, выполнить наш собственный обработчик ошибок.
Продемонстрируем вышесказанное на модифицированном скрипте index.php:
<?php
/**
* Обработчик ошибок
* @param int $errno уровень ошибки
* @param string $errstr сообщение об ошибке
* @param string $errfile имя файла, в котором произошла ошибка
* @param int $errline номер строки, в которой произошла ошибка
* @return boolean
*/
function error_handler($errno, $errstr, $errfile, $errline)
{
// если ошибка попадает в отчет (при использовании оператора "@" error_reporting() вернет 0)
if (error_reporting() & $errno)
{
$errors = array(
E_ERROR => 'E_ERROR',
E_WARNING => 'E_WARNING',
E_PARSE => 'E_PARSE',
E_NOTICE => 'E_NOTICE',
E_CORE_ERROR => 'E_CORE_ERROR',
E_CORE_WARNING => 'E_CORE_WARNING',
E_COMPILE_ERROR => 'E_COMPILE_ERROR',
E_COMPILE_WARNING => 'E_COMPILE_WARNING',
E_USER_ERROR => 'E_USER_ERROR',
E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE',
E_STRICT => 'E_STRICT',
E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
E_DEPRECATED => 'E_DEPRECATED',
E_USER_DEPRECATED => 'E_USER_DEPRECATED',
);
// выводим свое сообщение об ошибке
echo "<b>{$errors[$errno]}</b>[$errno] $errstr ($errfile на $errline строке)<br />n";
}
// не запускаем внутренний обработчик ошибок PHP
return TRUE;
}
/**
* Функция перехвата фатальных ошибок
*/
function fatal_error_handler()
{
// если была ошибка и она фатальна
if ($error = error_get_last() AND $error['type'] & ( E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR))
{
// очищаем буффер (не выводим стандартное сообщение об ошибке)
ob_end_clean();
// запускаем обработчик ошибок
error_handler($error['type'], $error['message'], $error['file'], $error['line']);
}
else
{
// отправка (вывод) буфера и его отключение
ob_end_flush();
}
}
// определеяем уровень протоколирования ошибок
error_reporting(E_ALL | E_STRICT);
// определяем режим вывода ошибок
ini_set('display_errors', 'On');
// включаем буфферизацию вывода (вывод скрипта сохраняется во внутреннем буфере)
ob_start();
// устанавливаем пользовательский обработчик ошибок
set_error_handler("error_handler");
// регистрируем функцию, которая выполняется после завершения работы скрипта (например, после фатальной ошибки)
register_shutdown_function('fatal_error_handler');
require 'errors.php';
Не забываем, что ошибки смешанного типа, после объявления собственного обработчика ошибок, стали не фатальными. Плюс к этому, весь вывод скрипта до фатальной ошибки вместе с стандартным сообщением об ошибке будет сброшен.
Вообще, рассмотренный пример обработчика ошибок, обработкой, как таковой, не занимается, а только демонстрирует саму возможность. Дальнейшее его поведение зависит от ваших желаний и/или требований. Например, все случаи обращения к обработчику можно записывать в лог, а в случае фатальных ошибок, дополнительно, уведомлять об этом администратора ресурса.
Полезные ссылки
- Первоисточник: php.net/manual/ru/book.errorfunc.php
- Описание ошибок: php.net/manual/ru/errorfunc.constants.php
- Функции контроля вывода: php.net/manual/ru/ref.outcontrol.php
- Побитовые операторы: php.net/manual/ru/language.operators.bitwise.php и habrahabr.ru/post/134557
- Тематически близкая статья: habrahabr.ru/post/134499
Хотя PHP уже давно поддерживает обработку исключений, однако, по сравнению с Java эта поддержка была довольно слабой
Первоначальная поддержка обработки исключений была введена в язык с 5 версии PHP, с двумя простыми встроенными классами исключений — Exception и ErrorException, с поддержкой дополнительных классов через SPL. Идея этого поста состоит в том, чтобы представить читателям современные возможности обработки исключений PHP.
Новый интерфейс
Хотя PHP 7 предоставляет классы Error и Exception, давайте сначала затронем интерфейс Throwable . И Error и Exception классы реализуют Throwable интерфейс — это основа для любого объекта , который может быть брошен с помощью оператора throw. Единственное, что он не может быть реализован непосредственно в классах пользовательского пространства, только через расширение класса Exception. Кроме того, он обеспечивает единую точку для отлова обоих типов ошибок в одном выражении:
<?php
try {
// ваш код
} catch (Throwable $e) {
echo 'Очень хороший способ отловить исключения и ошибки';
}
Список доступных встроенных классов исключений начиная с PHP 7.4:
- Exception
- ErrorException
- Error
- ArgumentCountError
- ArithmeticError
- AssertionError
- DivisionByZeroError
- CompileError
- ParseError
- TypeError
Дополнительные классы исключений можно найти в стандартной библиотеке PHP . И наиболее заметным из расширений JSON является класс JsonException.
THROWABLE
Интерфейс Throwable PHP 7:
interface Throwable
{
public function getMessage(): string; // Error reason
public function getCode(): int; // Error code
public function getFile(): string; // Error begin file
public function getLine(): int; // Error begin line
public function getTrace(): array; // Return stack trace as array like debug_backtrace()
public function getTraceAsString(): string; // Return stack trace as string
public function getPrevious(): Throwable; // Return previous `Trowable`
public function __toString(): string; // Convert into string
}
Вот иерархия Throwable:
interface Throwable
|- Error implements Throwable
|- ArithmeticError extends Error
|- DivisionByZeroError extends ArithmeticError
|- AssertionError extends Error
|- ParseError extends Error
|- TypeError extends Error
|- ArgumentCountError extends TypeError
|- Exception implements Throwable
|- ClosedGeneratorException extends Exception
|- DOMException extends Exception
|- ErrorException extends Exception
|- IntlException extends Exception
|- LogicException extends Exception
|- BadFunctionCallException extends LogicException
|- BadMethodCallException extends BadFunctionCallException
|- DomainException extends LogicException
|- InvalidArgumentException extends LogicException
|- LengthException extends LogicException
|- OutOfRangeException extends LogicException
|- PharException extends Exception
|- ReflectionException extends Exception
|- RuntimeException extends Exception
|- OutOfBoundsException extends RuntimeException
|- OverflowException extends RuntimeException
|- PDOException extends RuntimeException
|- RangeException extends RuntimeException
|- UnderflowException extends RuntimeException
|- UnexpectedValueException extends RuntimeException
Ошибка, почему?
В предыдущих версиях PHP ошибки обрабатывались совершенно иначе, чем исключения. Если возникала ошибка, то пока она не была фатальной, она могла быть обработана пользовательской функцией.
Проблема заключалась в том, что было несколько фатальных ошибок, которые не могли быть обработаны определяемым пользователем обработчиком ошибок. Это означало, что вы не могли корректно обрабатывать фатальные ошибки в PHP. Было несколько побочных эффектов, которые были проблематичными, такие как потеря контекста времени выполнения, деструкторы не вызывались, да и вообще иметь дело с ними было неудобно. В PHP 7 фатальные ошибки теперь являются исключениями, и мы можем легко их обработать. Фатальные ошибки приводят к возникновению исключений. Вам необходимо обрабатывать нефатальные ошибки с помощью функции обработки ошибок.
Вот пример ловли фатальной ошибки в PHP 7.1. Обратите внимание, что нефатальная ошибка не обнаружена.
<?php
try {
// будет генерировать уведомление, которое не будет поймано
echo $someNotSetVariable;
// фатальная ошибка, которая сейчас на самом деле ловится
someNoneExistentFunction();
} catch (Error $e) {
echo "Error caught: " . $e->getMessage();
}
Этот скрипт выведет сообщение об ошибке при попытке доступа к недопустимой переменной. Попытка вызвать функцию, которая не существует, приведет к фатальной ошибке в более ранних версиях PHP, но в PHP 7.1 вы можете ее перехватить. Вот вывод для скрипта:
Notice: Undefined variable: someNotSetVariable on line 3
Error caught: Call to undefined function someNoneExistentFunction()
Константы ошибок
В PHP много констант, которые используются в отношении ошибок. Эти константы используются при настройке PHP для скрытия или отображения ошибок определенных классов.
Вот некоторые из наиболее часто встречающихся кодов ошибок:
- E_DEPRECATED — интерпретатор сгенерирует этот тип предупреждений, если вы используете устаревшую языковую функцию. Сценарий обязательно продолжит работать без ошибок.
- E_STRICT — аналогично E_DEPRECATED, — указывает на то, что вы используете языковую функцию, которая не является стандартной в настоящее время и может не работать в будущем. Сценарий будет продолжать работать без каких-либо ошибок.
- E_PARSE — ваш синтаксис не может быть проанализирован, поэтому ваш скрипт не запустится. Выполнение скрипта даже не запустится.
- E_NOTICE — движок просто выведет информационное сообщение. Выполнение скрипта не прервется, и ни одна из ошибок не будет выдана.
- E_ERROR — скрипт не может продолжить работу, и завершится. Выдает ошибки, а как они будут обрабатываться, зависит от обработчика ошибок.
- E_RECOVERABLE_ERROR — указывает на то, что, возможно, произошла опасная ошибка, и движок работает в нестабильном состоянии. Дальнейшее выполнение зависит от обработчика ошибок, и ошибка обязательно будет выдана.
Полный список констант можно найти в руководстве по PHP.
Функция обработчика ошибок
Функция set_error_handler() используется, чтобы сообщить PHP как обрабатывать стандартные ошибки, которые не являются экземплярами класса исключений Error. Вы не можете использовать функцию обработчика ошибок для фатальных ошибок. Исключения ошибок должны обрабатываться с помощью операторов try/catch. set_error_handler() принимает callback функцию в качестве своего параметра. Callback-функции в PHP могут быть заданы двумя способами: либо строкой, обозначающей имя функции, либо передачей массива, который содержит объект и имя метода (именно в этом порядке). Вы можете указать защищенные и приватные методы для callable в объекте. Вы также можете передать значение null, чтобы указать PHP вернуться к использованию стандартного механизма обработки ошибок. Если ваш обработчик ошибок не завершает программу и возвращает результат, ваш сценарий будет продолжать выполняться со строки, следующей за той, где произошла ошибка.
PHP передает параметры в вашу функцию обработчика ошибок. Вы можете опционально объявить их в сигнатуре функции, если хотите использовать их в своей функции.
Вот пример:
<?php
function myCustomErrorHandler(int $errNo, string $errMsg, string $file, int $line) {
echo "Ух ты, мой обработчик ошибок получил #[$errNo] в [$file] на [$line]: [$errMsg]";
}
set_error_handler('myCustomErrorHandler');
try {
why;
} catch (Throwable $e) {
echo 'И моя ошибка: ' . $e->getMessage();
}
Если вы запустите этот код в PHP-консоли php -a, вы должны получить похожий вывод:
Error #[2] occurred in [php shell code] at line [3]: [Use of undefined constant why - assumed 'why' (this will throw an Error in a future version of PHP)]
Самые известные PHP библиотеки , которые делают обширное использование РНР set_error_handler() и могут сделать хорошие представления исключений и ошибок являются whoops, и Symony Debug, ErrorHandler компоненты. Я смело рекомендую использовать один из них. Если не собираетесь их использовать в своем проекте, то вы всегда можете черпать вдохновение из их кода. В то время как компонент Debug широко используется в экосистеме Symfony, Whoops остается библиотекой выбора для фреймворка Laravel .
Для подробного и расширенного использования, пожалуйста, обратитесь к руководству по PHP для обработчика ошибок.
Отображение или подавление нефатальной ошибки
Когда ваше приложение выходит в продакшн, логично, что вы хотите скрыть все системные сообщения об ошибках во время работы, и ваш код должен работать без генерации предупреждений или сообщений. Если вы собираетесь показать сообщение об ошибке, убедитесь, что оно сгенерировано и не содержит информации, которая может помочь злоумышленнику проникнуть в вашу систему.
В вашей среде разработки вы хотите, чтобы все ошибки отображались, чтобы вы могли исправить все проблемы, с которыми они связаны, но в процессе работы вы хотите подавить любые системные сообщения, отправляемые пользователю.
Для этого вам нужно настроить PHP, используя следующие параметры в вашем файле php.ini:
- display_errors – может быть установлен в false для подавления сообщений
- log_errors – может использоваться для хранения сообщений об ошибках в файлах журнала
- error_reporting – можно настроить, какие ошибки вызывают отчет
Лучше всего корректно обрабатывать ошибки в вашем приложении. В производственном процессе вы должны скорее регистрировать необработанные ошибки, чем разрешать их отображение пользователю. Функция error_log() может использоваться для отправки сообщения одной из определенных процедур обработки ошибок. Вы также можете использовать функцию error_log() для отправки электронных писем, но лично вы бы предпочли использовать хорошее решение для регистрации ошибок и получения уведомлений при возникновении ошибок, например Sentry или Rollbar .
Существует вещь, называемая оператором контроля ошибок ( @ ), который по своей сути может игнорировать и подавлять ошибки. Использование очень простое — просто добавьте любое выражение PHP с символом «собаки», и сгенерированная ошибка будет проигнорирована. Хотя использование этого оператора может показаться интересным, я призываю вас не делать этого. Мне нравится называть это живым пережитком прошлого.
Больше информации для всех функций, связанных с ошибками PHP, можно найти в руководстве.
Исключения (Exceptions)
Исключения являются основной частью объектно-ориентированного программирования и впервые были представлены в PHP 5.0. Исключением является состояние программы, которое требует специальной обработки, поскольку оно не выполняется ожидаемым образом. Вы можете использовать исключение, чтобы изменить поток вашей программы, например, чтобы прекратить что-либо делать, если некоторые предварительные условия не выполняются.
Исключение будет возникать в стеке вызовов, если вы его не перехватите. Давайте посмотрим на простой пример:
try {
print "это наш блок попыток n";
throw new Exception();
} catch (Exception $e) {
print "что-то пошло не так, есть улов!";
} finally {
print "эта часть всегда выполняется";
}
PHP включает в себя несколько стандартных типов исключений, а стандартная библиотека PHP (SPL) включает в себя еще несколько. Хотя вам не нужно использовать эти исключения, это означает, что вы можете использовать более детальное обнаружение ошибок и отчеты. Классы Exception и Error реализуют интерфейс Throwable и, как и любые другие классы, могут быть расширены. Это позволяет вам создавать гибкие иерархии ошибок и адаптировать обработку исключений. Только класс, который реализует класс Throwable, может использоваться с ключевым словом throw. Другими словами, вы не можете объявить свой собственный базовый класс и затем выбросить его как исключение.
Надежный код может встретить ошибку и справиться с ней. Разумная обработка исключений повышает безопасность вашего приложения и облегчает ведение журнала и отладку. Управление ошибками в вашем приложении также позволит вам предложить своим пользователям лучший опыт. В этом разделе мы рассмотрим, как отлавливать и обрабатывать ошибки, возникающие в вашем коде.
Ловля исключений
Вы должны использовать try/catch структуру:
<?php
class MyCustomException extends Exception { }
function throwMyCustomException() {
throw new MyCustomException('Здесь что-то не так.');
}
try {
throwMyCustomException();
} catch (MyCustomException $e) {
echo "Ваше пользовательское исключение поймано";
echo $e->getMessage();
} catch (Exception $e) {
echo "Стандартное исключение PHP";
}
Как видите, есть два предложения catch. Исключения будут сопоставляться с предложениями сверху вниз, пока тип исключения не будет соответствовать предложению catch. Эта очень простая функция throwMyCustomException() генерирует исключение MyCustomException, и мы ожидаем, что оно будет перехвачено в первом блоке. Любые другие исключения, которые произойдут, будут перехвачены вторым блоком. Здесь мы вызываем метод getMessage() из базового класса Exception. Вы можете найти больше информации о дополнительном методе в Exception PHP docs.
Кроме того, можно указать несколько исключений, разделяя их трубой ( | ).
Давайте посмотрим на другой пример:
<?php
class MyCustomException extends Exception { }
class MyAnotherCustomException extends Exception { }
try {
throw new MyAnotherCustomException;
} catch (MyCustomException | MyAnotherCustomException $e) {
echo "Caught : " . get_class($e);
}
Этот очень простой блок catch будет перехватывать исключения типа MyCustomException и MyAnotherCustomException.
Немного более продвинутый сценарий:
// exceptions.php
use SymfonyComponentHttpKernelExceptionNotFoundHttpException;
try {
throw new NotFoundHttpException();
} catch (Exception $e) {
echo 1;
} catch (NotFoundHttpException $e) {
echo 2;
} catch (Exception $e) {
echo 3;
} finally {
echo 4;
}
Это ваш окончательный ответ?
В PHP 5.5 и более поздних, блок finally также может быть указан после или вместо блоков catch. Код внутри блока finally всегда будет выполняться после блоков try и catch независимо от того, было ли выброшено исключение, и до возобновления нормального выполнения. Одним из распространенных применений блока finally является закрытие соединения с базой данных, но, наконец, его можно использовать везде, где вы хотите, чтобы код всегда выполнялся.
<?php
class MyCustomException extends Exception { }
function throwMyCustomException() {
throw new MyCustomException('Здесь что-то не так');
}
try {
throwMyCustomException();
} catch (MyCustomException $e) {
echo "Ваше пользовательское исключение поймано ";
echo $e->getMessage();
} catch (Exception $e) {
echo "Стандартное исключение PHP";
} finally {
echo "Я всегда тут";
}
Вот хороший пример того, как работают операторы PHP catch/finally:
<?php
try {
try {
echo 'a-';
throw new exception();
echo 'b-';
} catch (Exception $e) {
echo 'пойманный-';
throw $e;
} finally {
echo 'завершенный-';
}
} catch (Exception $e) {
echo 'конец-';
}
Функция обработчика исключений
Любое исключение, которое не было обнаружено, приводит к фатальной ошибке. Если вы хотите изящно реагировать на исключения, которые не перехватываются в блоках перехвата, вам нужно установить функцию в качестве обработчика исключений по умолчанию.
Для этого вы используете функцию set_exception_handler() , которая принимает вызываемый элемент в качестве параметра. Ваш сценарий завершится после того, как вызов будет выполнен.
Функция restore_exception_handler() вернет обработчик исключений к его предыдущему значению.
<?php
class MyCustomException extends Exception { }
function exception_handler($exception) {
echo "Uncaught exception: " , $exception->getMessage(), "n";
}
set_exception_handler('exception_handler');
try {
throw new Exception('Uncaught Exception');
} catch (MyCustomException $e) {
echo "Ваше пользовательское исключение поймано ";
echo $e->getMessage();
} finally {
echo "Я всегда тут";
}
print "Не выполнено";
Здесь простая функция exception_handler будет выполняться после блока finally, когда ни один из типов исключений не был сопоставлен. Последний вывод никогда не будет выполнен.
Для получения дополнительной информации обратитесь к документации PHP.
Старый добрый «T_PAAMAYIM_NEKUDOTAYIM»
Вероятно, это было самое известное сообщение об ошибке PHP. В последние годы было много споров по этому поводу. Вы можете прочитать больше в отличном сообщении в блоге от Фила Осетра .
Сегодня я с гордостью могу сказать, что если вы запустите этот код с PHP 7, то сообщение о T_PAAMAYIM_NEKUDOTAYIM больше не будет:
<?php
class foo
{
static $bar = 'baz';
}
var_dump('foo'::$bar);
// Output PHP < 7.0:
// PHP Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM) in php shell code on line 1
// Output PHP > 7.0:
// string(3) "baz"
?>
В заключении
Со времени первого внедрения обработки исключений в PHP прошло много лет, пока мы не получили гораздо более надежную и зрелую обработку исключений, чем в Java. Обработка ошибок в PHP 7 получила много внимания, что делает его хорошим, открывая пространство для будущих улучшений, если мы действительно с сегодняшней точки зрения нуждаемся в них.
DEV environment
This always works for me:
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
However, this doesn’t make PHP to show parse errors occurred in the same file — the only way to show those errors is to modify your php.ini with this line:
display_errors = on
(if you don’t have access to php.ini
, then putting this line in .htaccess
might work too):
php_flag display_errors 1
PROD environment
Note that above recommentdtion is only suitable for the dev environment. On a live site it must be
display_errors = off
log_errors = on
And then you’ll be able to see all errors in the error log. See Where to find PHP error log
AJAX calls
In case of AJAX call, on a dev server open DevTools (F12), then Network tab.
Then initiate the request which result you want to see, and it will appear in the Network tab. Click on it and then the Response tab. There you will see the exact output.
While on a live server just check the error log all the same.
answered Jan 29, 2014 at 11:25
Fancy JohnFancy John
38k3 gold badges27 silver badges27 bronze badges
16
You can’t catch parse errors in the same file where error output is enabled at runtime, because it parses the file before actually executing anything (and since it encounters an error during this, it won’t execute anything). You’ll need to change the actual server configuration so that display_errors is on and the approriate error_reporting level is used. If you don’t have access to php.ini, you may be able to use .htaccess or similar, depending on the server.
This question may provide additional info.
answered Jun 27, 2009 at 19:14
Michael MadsenMichael Madsen
54.1k8 gold badges72 silver badges83 bronze badges
0
Inside your php.ini:
display_errors = on
Then restart your web server.
j0k
22.5k28 gold badges79 silver badges89 bronze badges
answered Jan 8, 2013 at 9:27
user1803477user1803477
1,6151 gold badge10 silver badges4 bronze badges
5
To display all errors you need to:
1. Have these lines in the PHP script you’re calling from the browser (typically index.php
):
error_reporting(E_ALL);
ini_set('display_errors', '1');
2.(a) Make sure that this script has no syntax errors
—or—
2.(b) Set display_errors = On
in your php.ini
Otherwise, it can’t even run those 2 lines!
You can check for syntax errors in your script by running (at the command line):
php -l index.php
If you include the script from another PHP script then it will display syntax errors in the included script. For example:
index.php
error_reporting(E_ALL);
ini_set('display_errors', '1');
// Any syntax errors here will result in a blank screen in the browser
include 'my_script.php';
my_script.php
adjfkj // This syntax error will be displayed in the browser
answered Jan 29, 2014 at 9:52
andreandre
1,8311 gold badge16 silver badges8 bronze badges
2
Some web hosting providers allow you to change PHP parameters in the .htaccess
file.
You can add the following line:
php_value display_errors 1
I had the same issue as yours and this solution fixed it.
answered May 18, 2013 at 15:01
KalhuaKalhua
5594 silver badges2 bronze badges
1
Warning: the below answer is factually incorrect. Nothing has been changed in error handling, uncaught exceptions are displayed just like other errors. Suggested approach must be used with caution, because it outputs errors unconditionally, despite the display_error setting and may pose a threat by revealing the sensitive information to an outsider on a live site.
You might find all of the settings for «error reporting» or «display errors» do not appear to work in PHP 7. That is because error handling has changed. Try this instead:
try{
// Your code
}
catch(Error $e) {
$trace = $e->getTrace();
echo $e->getMessage().' in '.$e->getFile().' on line '.$e->getLine().' called from '.$trace[0]['file'].' on line '.$trace[0]['line'];
}
Or, to catch exceptions and errors in one go (this is not backward compatible with PHP 5):
try{
// Your code
}
catch(Throwable $e) {
$trace = $e->getTrace();
echo $e->getMessage().' in '.$e->getFile().' on line '.$e->getLine().' called from '.$trace[0]['file'].' on line '.$trace[0]['line'];
}
answered Mar 28, 2016 at 19:26
Frank ForteFrank Forte
1,97119 silver badges18 bronze badges
9
This will work:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
answered May 5, 2014 at 13:23
Mahendra JellaMahendra Jella
5,4101 gold badge33 silver badges38 bronze badges
1
Use:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
This is the best way to write it, but a syntax error gives blank output, so use the console to check for syntax errors. The best way to debug PHP code is to use the console; run the following:
php -l phpfilename.php
answered May 4, 2016 at 19:14
Abhijit JagtapAbhijit Jagtap
2,7202 gold badges29 silver badges43 bronze badges
0
Set this in your index.php file:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
answered Sep 26, 2017 at 12:32
Sumit GuptaSumit Gupta
5674 silver badges12 bronze badges
0
Create a file called php.ini in the folder where your PHP file resides.
Inside php.ini add the following code (I am giving an simple error showing code):
display_errors = on
display_startup_errors = on
answered Mar 31, 2015 at 18:38
NavyaKumarNavyaKumar
5875 silver badges3 bronze badges
In order to display a parse error, instead of setting display_errors
in php.ini you can use a trick: use include.
Here are three pieces of code:
File: tst1.php
<?php
error_reporting(E_ALL);
ini_set('display_errors', 'On');
// Missing " and ;
echo "Testing
When running this file directly, it will show nothing, given display_errors
is set to 0 in php.ini.
Now, try this:
File: tst2.php
<?php
error_reporting(E_ALL);
ini_set('display_errors', 'On');
include ("tst3.php");
File: tst3.php
<?php
// Missing " and ;
echo "Testing
Now run tst2.php which sets the error reporting, and then include tst3. You will see:
Parse error: syntax error, unexpected end of file, expecting variable (T_VARIABLE) or ${ (T_DOLLAR_OPEN_CURLY_BRACES) or {$ (T_CURLY_OPEN) in tst3.php on line 4
answered May 20, 2017 at 12:07
PeterPeter
1,23719 silver badges32 bronze badges
4
If, despite following all of the above answers (or you can’t edit your php.ini file), you still can’t get an error message, try making a new PHP file that enables error reporting and then include the problem file. eg:
error_reporting(E_ALL);
ini_set('display_errors', 1);
require_once('problem_file.php');
Despite having everything set properly in my php.ini
file, this was the only way I could catch a namespace error. My exact scenario was:
//file1.php
namespace ab;
class x {
...
}
//file2.php
namespace cd;
use cdx; //Dies because it's not sure which 'x' class to use
class x {
...
}
answered Apr 24, 2015 at 2:55
jxmallettjxmallett
4,0671 gold badge28 silver badges35 bronze badges
2
I would usually go with the following code in my plain PHP projects.
if(!defined('ENVIRONMENT')){
define('ENVIRONMENT', 'DEVELOPMENT');
}
$base_url = null;
if (defined('ENVIRONMENT'))
{
switch (ENVIRONMENT)
{
case 'DEVELOPMENT':
$base_url = 'http://localhost/product/';
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
break;
case 'PRODUCTION':
$base_url = 'Production URL'; /* https://google.com */
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
ini_set('log_errors', 1); // Mechanism to log errors
break;
default:
exit('The application environment is not set correctly.');
}
}
answered Feb 1, 2017 at 7:16
If you somehow find yourself in a situation where you can’t modifiy the setting via php.ini
or .htaccess
you’re out of luck for displaying errors when your PHP scripts contain parse errors. You’d then have to resolve to linting the files on the command line like this:
find . -name '*.php' -type f -print0 | xargs -0 -n1 -P8 php -l | grep -v "No syntax errors"
If your host is so locked down that it does not allow changing the value via php.ini
or .htaccess
, it may also disallow changing the value via ini_set
. You can check that with the following PHP script:
<?php
if( !ini_set( 'display_errors', 1 ) ) {
echo "display_errors cannot be set.";
} else {
echo "changing display_errors via script is possible.";
}
answered Jan 11, 2016 at 12:11
chiborgchiborg
26.7k14 gold badges96 silver badges115 bronze badges
1
You can do something like below:
Set the below parameters in your main index file:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
Then based on your requirement you can choose which you want to show:
For all errors, warnings and notices:
error_reporting(E_ALL); OR error_reporting(-1);
For all errors:
error_reporting(E_ERROR);
For all warnings:
error_reporting(E_WARNING);
For all notices:
error_reporting(E_NOTICE);
For more information, check here.
answered Feb 1, 2017 at 7:33
Binit GhetiyaBinit Ghetiya
1,9092 gold badges21 silver badges31 bronze badges
1
You can add your own custom error handler, which can provide extra debug information. Furthermore, you can set it up to send you the information via email.
function ERR_HANDLER($errno, $errstr, $errfile, $errline){
$msg = "<b>Something bad happened.</b> [$errno] $errstr <br><br>
<b>File:</b> $errfile <br>
<b>Line:</b> $errline <br>
<pre>".json_encode(debug_backtrace(), JSON_PRETTY_PRINT)."</pre> <br>";
echo $msg;
return false;
}
function EXC_HANDLER($exception){
ERR_HANDLER(0, $exception->getMessage(), $exception->getFile(), $exception->getLine());
}
function shutDownFunction() {
$error = error_get_last();
if ($error["type"] == 1) {
ERR_HANDLER($error["type"], $error["message"], $error["file"], $error["line"]);
}
}
set_error_handler ("ERR_HANDLER", E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED);
register_shutdown_function("shutdownFunction");
set_exception_handler("EXC_HANDLER");
answered Jun 4, 2017 at 14:41
lintabálintabá
7319 silver badges18 bronze badges
Accepted asnwer including extra options. In PHP files for in my DEVELOPMENT apache vhost (.htaccess if you can ensure it doesn’t get into production):
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
However, this doesn’t make PHP to show parse errors — the only way to show those errors is to modify your php.ini with this line:
display_errors = on
(if you don’t have access to php.ini
, then putting this line in .htaccess
might work too):
// I've added some extra options that set E_ALL as per https://www.php.net/manual/en/errorfunc.configuration.php.
php_flag log_errors on
php_flag display_errors on
php_flag display_startup_errors on
php_value error_reporting 2147483647
php_value error_log /var/www/mywebsite.ext/logs/php.error.log
answered Jan 8, 2022 at 22:17
This code on top should work:
error_reporting(E_ALL);
However, try to edit the code on the phone in the file:
error_reporting =on
answered May 9, 2017 at 3:28
Joel WemboJoel Wembo
8146 silver badges10 bronze badges
The best/easy/fast solution that you can use if it’s a quick debugging, is to surround your code with catching exceptions. That’s what I’m doing when I want to check something fast in production.
try {
// Page code
}
catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "n";
}
answered Mar 27, 2017 at 2:31
XakiruXakiru
2,5261 gold badge15 silver badges11 bronze badges
3
<?php
// Turn off error reporting
error_reporting(0);
// Report runtime errors
error_reporting(E_ERROR | E_WARNING | E_PARSE);
// Report all errors
error_reporting(E_ALL);
// Same as error_reporting(E_ALL);
ini_set("error_reporting", E_ALL);
// Report all errors except E_NOTICE
error_reporting(E_ALL & ~E_NOTICE);
?>
While your site is live, the php.ini
file should have display_errors disabled for security reasons. However, for the development environment, display_errors can be enabled for troubleshooting.
answered May 24, 2018 at 8:48
pardeeppardeep
3591 gold badge5 silver badges7 bronze badges
0
Just write:
error_reporting(-1);
answered Jan 13, 2017 at 18:56
jewelhuqjewelhuq
1,20014 silver badges19 bronze badges
0
If you have Xdebug installed you can override every setting by setting:
xdebug.force_display_errors = 1;
xdebug.force_error_reporting = -1;
force_display_errors
Type: int, Default value: 0, Introduced in Xdebug >= 2.3 If this
setting is set to 1 then errors will always be displayed, no matter
what the setting of PHP’s display_errors is.force_error_reporting
Type: int, Default value: 0, Introduced in Xdebug >= 2.3
This setting is a bitmask, like error_reporting. This bitmask will be logically ORed with the bitmask represented by error_reporting to dermine which errors should be displayed. This setting can only be made in php.ini and allows you to force certain errors from being shown no matter what an application does with ini_set().
answered Oct 19, 2017 at 5:45
If it is on the command line, you can run php
with -ddisplay_errors=1
to override the setting in php.ini
:
php -ddisplay_errors=1 script.php
answered Oct 24, 2019 at 23:11
gvlasovgvlasov
18.4k20 gold badges73 silver badges109 bronze badges
Report all errors except E_NOTICE
error_reporting(E_ALL & ~E_NOTICE);
Display all PHP errors
error_reporting(E_ALL); or ini_set('error_reporting', E_ALL);
Turn off all error reporting
error_reporting(0);
answered Dec 31, 2019 at 10:07
In Unix CLI, it’s very practical to redirect only errors to a file:
./script 2> errors.log
From your script, either use var_dump()
or equivalent as usual (both STDOUT and STDERR will receive the output), but to write only in the log file:
fwrite(STDERR, "Debug infosn"); // Write in errors.log^
Then from another shell, for live changes:
tail -f errors.log
or simply
watch cat errors.log
answered Nov 26, 2019 at 2:28
NVRMNVRM
11.1k1 gold badge86 silver badges85 bronze badges
2
If you are on a SharedHosting plan (like on hostgator)… simply adding
php_flag display_errors 1
into a .htaccess file and uploading it to the remote folder may not yield the actual warnings/errors that were generated on the server.
What you will also need to do is edit the php.ini
This is how you do it via cPanel (tested on hostgator shared hosting
plan)
After logging into your cPanel, search for MultiPHP INI Editor.
It is usually found under the SOFTWARE section in your cPanel list of items.
On the MultiPHP INI Editor page …you can stay on the basic mode tab and just check the button on the line that says display_errors.
Then click the Apply button to save.
IMPORTANT: Just remember to turn it back off when you are done debugging; because this is not recommended for public servers.
answered Mar 13, 2022 at 17:21
Really Nice CodeReally Nice Code
1,1141 gold badge13 silver badges22 bronze badges
As it is not clear what OS you are on these are my 2 Windows cents.
If you are using XAMPP you need to manually create the logs
folder under C:xamppphp
. Not your fault, ApacheFriends ommitted this.
To read and follow this file do.
Get-Content c:xamppphplogsphp_error_log -Wait
To do this in VSCode create a task in .vscodetasks.json
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Monitor php errors",
"type": "shell",
"command": "Get-Content -Wait c:\xampp\php\logs\php_error_log",
"runOptions": {
"runOn": "folderOpen"
}
}
]
and have it run on folder load.
answered Dec 3, 2022 at 14:40
theking2theking2
2,0071 gold badge25 silver badges32 bronze badges