Перейти к содержимому
Теория · Ошибки и исключения · урок 1 из 8

Предупреждения, фатальные ошибки и Error

Чему вы научитесь

Чему вы научитесь:

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

Представьте курьера, который разносит посылки по квартирам большого дома. Обход редко проходит идеально, но неприятности бывают разного веса:

  • Хозяина нет дома. Курьер оставляет на двери записку и идёт к следующей квартире.
  • Посылку вручить нельзя: такого получателя нет. Курьер несёт её обратно вверх по лестнице, пока кто-нибудь не откроет дверь и не заберёт её. Если не откроет никто, обход заканчивается.
  • В доме погас свет и встал лифт. Обход окончен, что бы курьер ни делал.

Программа на PHP — такой же обход: строки выполняются одна за другой. В первой теме вы уже встречали Warning и Fatal error. Теперь разберём, какие сбои бывают в PHP 8 и чем они отличаются.

Записка на двери: предупреждение

Как вы уже знаете, после предупреждения программа продолжает работу. Посмотрим на чтение ключа, которого нет в массиве:

PHP
<?php

$prices = ['tea' => 30];
echo 'start', "\n"; // start
echo $prices['coffee'], "\n"; // ✗
echo 'end', "\n"; // end
TEXT
Warning: Undefined array key "coffee"

Разберём по строкам:

  1. Первый echo печатает start.
  2. Ключа 'coffee' в массиве нет. PHP печатает предупреждение, подставляет null, и echo выводит пустую строку.
  3. Программа идёт дальше и печатает 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
<?php

echo 'start', "\n"; // start
echo intdiv(10, 0), "\n"; // ✗
echo 'end', "\n";
TEXT
Fatal error: Uncaught DivisionByZeroError: Division by zero

start напечатано, а end — нет. Слово Uncaught значит «непойманный»: PHP бросил объект DivisionByZeroError, но в программе его никто не поймал.

Брошенный объект можно поймать, и тогда программа продолжит работу. Фатальной ошибкой он становится, только если до самого верха его не поймал никто.

Здесь картинка с курьером перестаёт работать. Настоящий курьер сам решает, какая неприятность мелкая. PHP ничего не решает: для каждого сбоя заранее определено, будет ли это записка или брошенный объект.

Конец обхода: настоящая фатальная ошибка

Некоторые сбои PHP не бросает, а сразу останавливает программу. Например, когда программе не хватило памяти, появляется Fatal error: Allowed memory size of … bytes exhausted, и поймать такую ошибку нельзя. Так же ведёт себя ошибка разбора в файле, который вы запускаете: из него ещё не выполнилось ни одной строки.

Чем предупреждение отличается от фатальной ошибки и от брошенного объекта — частый вопрос на собеседовании. Ответ укладывается в три пункта:

  • предупреждение сообщает о проблеме, и программа идёт дальше;
  • фатальная ошибка останавливает программу сразу;
  • брошенный объект летит назад по цепочке вызовов и останавливает программу, только если его никто не поймал.

Сообщения в разработке и на сервере

Где появятся эти сообщения, решает файл настроек PHP — php.ini:

  • На вашем компьютере в настройках для разработки включён параметр display_errors, и сообщения печатаются прямо в вывод, как в примерах курса.
  • На рабочем сервере он выключен. Сообщения уходят в журнал ошибок — файл, который читает только владелец сайта, а посетитель видит пустую страницу или страницу ошибки.

Так делают ради безопасности: сообщение показывает пути к файлам и номера строк, а посетителю их видеть незачем.

Частая ошибка

Предупреждение пропускают, потому что программа «всё равно работает»:

PHP
<?php

$price = 120;
$total = $prise * 2; // ✗
echo 'Total: ', $total, "\n"; // Total: 0
TEXT
Warning: Undefined variable $prise

Из-за опечатки в имени PHP прочитал несуществующую переменную как null, а null * 2 — это 0. Программа не остановилась и напечатала неверную сумму. В разработке вы увидите предупреждение, а на сервере оно молча уйдёт в журнал.

Читайте предупреждения и исправляйте их сразу: здесь нужно написать $price вместо $prise.

Главное

  • Warning, Notice и Deprecated — записки: PHP сообщает о проблеме и выполняет программу дальше.
  • При большинстве сбоев движка PHP бросает объект (TypeError, DivisionByZeroError); непойманный, он даёт Fatal error: Uncaught ….
  • Нехватку памяти и ошибку разбора запущенного файла поймать нельзя: программа останавливается сразу.
  • В разработке сообщения печатаются в вывод, а на рабочем сервере уходят в журнал ошибок.