#10. 6 php Класс Exception. Обработка пользовательских исключений на основе иерархии классов

Класс Exception

Все классы исключений, определенные пользователем, должны наследовать встроенный класс Exception, который имеет следующий интерфейс:

class Exception implements Throwable {
    /* Свойства */
    protected string $message = "";
    private string $string = "";
    protected int $code;
    protected string $file = "";
    protected int $line;
    private array $trace = [];
    private ?Throwable $previous = null;
    /* Методы */
    public __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
    final public getMessage(): string
    final public getPrevious(): ?Throwable
    final public getCode(): int
    final public getFile(): string
    final public getLine(): int
    final public getTrace(): array
    final public getTraceAsString(): string
    public __toString(): string
    private __clone(): void
}

Большинство методов класса Exception определены как final (то есть их не получится переопределить в наследуемых классах) и используются для обращения к защищенным свойствам класса.

Конструктор принимает три необязательных параметра: сообщение об ошибке, код исключения и предыдущее исключение. В теле конструктора заполняются свойства $file, $line и $trace, означающие соответственно имя файла, номер строки и стек вызовов функций — список имен функций, вызванных до момента генерации исключения, в порядке, обратном порядку их вызовов.

Метод __toString преобразует объект исключения в строку. При этом выводятся все свойства объекта, а также стек вызовов функций.

Обработка исключений на основе иерархии классов

Важным преимуществом использования исключений является возможность выполнять обработку ошибочных ситуаций в зависимости от их видовой принадлежности (на основе иерархии классов). В примере ниже в блоке catch с параметром типа FilesystemException (системные ошибки при работе с файлами) будут обработаны также все наследуемые от FilesystemException типы исключений.

<?php
class FilesystemException extends Exception
{
    //исключение - ошибка при работе с файлом
    private $name;
    public function __construct($name)
    {
        parent::__construct($name);
        $this->name = $name;
    }
    public function getName()
    {
        return $this->name;
    }
}

class FileNotFoundException extends FilesystemException
{
    //исключение - файл не найден
}

class FileWriteException extends FilesystemException
{
    //исключение - ошибка записи в файл
}

try {
    if (!file_exists("f")) {
        throw new FileNotFoundException("example");
    }
} catch (FilesystemException $e) {
    echo "Ошибка при работе с файлом ", $e->getName(), "<BR>";
}

Начиня с PHP 7.1.0 в блоке catch можно указать несколько различных видов обрабатываемых соответствующим способом исключений:

<?php
class FileNotFoundException extends FilesystemException
{
    //исключение - файл не найден
}

class PermissionDeniedException extends FilesystemException
{
    //исключение - доступ к файлу запрещен
}

try {
    if (!file_exists("f")) {
        throw new FileNotFoundException("example");
    }
} catch (FileNotFoundException | PermissionDeniedException $e) {
    echo "Файл ", $e->getName(), " не существует или недоступен<BR>";
}
    

"Ловить" исключения можно и по имени интерфейса, который реализуется классом исключения. Именно это позволяет поймать любое пользовательское и генерируемое встроенными операторами и функциями PHP исключение, указав реализуемый всеми исключениями интерфейс Throwable:

catch (Throwable $e) {
}