Предупреждения, фатальные ошибки и Error
Чему вы научитесь:
- отличать предупреждение, фатальную ошибку и брошенный объект
Errorпо сообщению PHP; - бросать и ловить исключения через
throw,tryиcatch; - понимать, какой
catchпоймаетException, а какой —Error; - выполнять код в
finallyпри любом исходе и объявлять свои классы исключений.

Представьте курьера, который разносит посылки по квартирам большого дома. Обход редко проходит идеально, но неприятности бывают разного веса:
- Хозяина нет дома. Курьер оставляет на двери записку и идёт к следующей квартире.
- Посылку вручить нельзя: такого получателя нет. Курьер несёт её обратно вверх по лестнице, пока кто-нибудь не откроет дверь и не заберёт её. Если не откроет никто, обход заканчивается.
- В доме погас свет и встал лифт. Обход окончен, что бы курьер ни делал.
Программа на PHP — такой же обход: строки выполняются одна за другой. В первой теме вы уже встречали Warning и Fatal error. Теперь разберём, какие сбои бывают в PHP 8 и чем они отличаются.
Записка на двери: предупреждение
Как вы уже знаете, после предупреждения программа продолжает работу. Посмотрим на чтение ключа, которого нет в массиве:
<?php
$prices = ['tea' => 30];
echo 'start', "\n"; // start
echo $prices['coffee'], "\n"; // ✗
echo 'end', "\n"; // endWarning: Undefined array key "coffee"Разберём по строкам:
- Первый
echoпечатаетstart. - Ключа
'coffee'в массиве нет. PHP печатает предупреждение, подставляетnull, иechoвыводит пустую строку. - Программа идёт дальше и печатает
end.
У предупреждения есть два родственника, и после них программа тоже продолжает работу:
Deprecatedзначит «устарело»: код работает сейчас, но перестанет работать в одной из следующих версий PHP. Например,strlen(null)даётDeprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated.Notice— самая лёгкая пометка.
Посылка назад: брошенная ошибка
Движок — внутренняя часть PHP, которая выполняет код. Если он не может выполнить строку, то с версии 7 PHP чаще всего бросает объект с описанием сбоя: отправляет его назад по цепочке вызовов, как посылку вверх по лестнице. Класс объекта называет сбой:
DivisionByZeroError— деление на ноль;TypeError— аргумент не того типа, например строка'four'для параметраint;ArgumentCountError— аргументов меньше, чем нужно функции;Error— например, вызов несуществующей функцииpritn().
Пусть программа делит на ноль:
<?php
echo 'start', "\n"; // start
echo intdiv(10, 0), "\n"; // ✗
echo 'end', "\n";Fatal error: Uncaught DivisionByZeroError: Division by zerostart напечатано, а end — нет. Слово Uncaught значит «непойманный»: PHP бросил объект DivisionByZeroError, но в программе его никто не поймал.
Брошенный объект можно поймать, и тогда программа продолжит работу. Фатальной ошибкой он становится, только если до самого верха его не поймал никто.
Здесь картинка с курьером перестаёт работать. Настоящий курьер сам решает, какая неприятность мелкая. PHP ничего не решает: для каждого сбоя заранее определено, будет ли это записка или брошенный объект.
Конец обхода: настоящая фатальная ошибка
Некоторые сбои PHP не бросает, а сразу останавливает программу. Например, когда программе не хватило памяти, появляется Fatal error: Allowed memory size of … bytes exhausted, и поймать такую ошибку нельзя. Так же ведёт себя ошибка разбора в файле, который вы запускаете: из него ещё не выполнилось ни одной строки.
Чем предупреждение отличается от фатальной ошибки и от брошенного объекта — частый вопрос на собеседовании. Ответ укладывается в три пункта:
- предупреждение сообщает о проблеме, и программа идёт дальше;
- фатальная ошибка останавливает программу сразу;
- брошенный объект летит назад по цепочке вызовов и останавливает программу, только если его никто не поймал.
Сообщения в разработке и на сервере
Где появятся эти сообщения, решает файл настроек PHP — php.ini:
- На вашем компьютере в настройках для разработки включён параметр
display_errors, и сообщения печатаются прямо в вывод, как в примерах курса. - На рабочем сервере он выключен. Сообщения уходят в журнал ошибок — файл, который читает только владелец сайта, а посетитель видит пустую страницу или страницу ошибки.
Так делают ради безопасности: сообщение показывает пути к файлам и номера строк, а посетителю их видеть незачем.
Частая ошибка
Предупреждение пропускают, потому что программа «всё равно работает»:
<?php
$price = 120;
$total = $prise * 2; // ✗
echo 'Total: ', $total, "\n"; // Total: 0Warning: Undefined variable $priseИз-за опечатки в имени PHP прочитал несуществующую переменную как null, а null * 2 — это 0. Программа не остановилась и напечатала неверную сумму. В разработке вы увидите предупреждение, а на сервере оно молча уйдёт в журнал.
Читайте предупреждения и исправляйте их сразу: здесь нужно написать $price вместо $prise.
Главное
Warning,NoticeиDeprecated— записки: PHP сообщает о проблеме и выполняет программу дальше.- При большинстве сбоев движка PHP бросает объект (
TypeError,DivisionByZeroError); непойманный, он даётFatal error: Uncaught …. - Нехватку памяти и ошибку разбора запущенного файла поймать нельзя: программа останавливается сразу.
- В разработке сообщения печатаются в вывод, а на рабочем сервере уходят в журнал ошибок.