Skip to content

Commit

Permalink
@ update doc
Browse files Browse the repository at this point in the history
  • Loading branch information
EdmondDantes committed Oct 26, 2024
1 parent bdfb464 commit 98dabcb
Show file tree
Hide file tree
Showing 12 changed files with 184 additions and 82 deletions.
2 changes: 1 addition & 1 deletion docs/00-Introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

```php
$exception = new BaseException(['template' => 'User {user} from {ip} is not allowed', 'user' => $user, 'ip' => $ip]);
$logger->error($exception->getMessage(), $exception->getExceptionData());
$logger->error($exception);
```

Это даёт возможность в дальнейшем анализировать журнал и понимать,
Expand Down
16 changes: 5 additions & 11 deletions docs/01-Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ The container is used to change the flag `is_loggable`:
class ClassNotExist extends BaseException
{
// This exception will be logged
protected $is_loggable = true;
protected $isLoggable = true;

/**
* ClassNotExist
Expand All @@ -111,8 +111,8 @@ class ClassNotExist extends BaseException
```php
class MyFatalException extends BaseException
{
// This exception has aspect: "fatal"
protected $is_fatal = true;
// This exception has an aspect: "fatal"
protected $isFatal = true;
}
```

Expand All @@ -123,14 +123,8 @@ class MyException extends BaseException
{
public function __construct($object)
{
$this->set_debug_data($object);
$this->setDebugData($object->toArray());
parent::__construct('its too bad!');
}
}
```

## BaseException static methods

## Registry

## StorageInterface
```
41 changes: 41 additions & 0 deletions docs/02-Paradigm.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,45 @@ final class UserNotAllowed extends \IfCastle\Exceptions\BaseException
в таком случае метаданные исключения будут использоваться для формирования атрибутов,
которые попадут в трейсер вместе с тегами и шаблоном сообщения.

## Исключения и теги

Теги позволяют сгруппировать исключения произвольным образом.

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

```php
final class MyException extends \IfCastle\Exceptions\BaseException
{
protected array $tags = ['system', 'service'];
}
```

Вы так же можете передать теги в конструкторе исключения.

```php
$exception = new MyException(['tags' => ['custom', 'tag']]);
$logger->error($exception);
```

Теги, добавленные в конструкторе, будут объединены с тегами, определёнными в классе исключения.

## Исключения и аспекты

Иногда нужно разделить разные исключения по особым типам обработки.
Например, некоторые исключения могут быть показаны пользователю, в то время, когда другие -- нет.

`BaseException` предлагает для этого специальный интерфейс: `ClientAvailableInterface`,
который указывает, что исключение может быть показано пользователю.

Интерфейс так же содержит дополнительные методы:
* `getClientMessage`
* `clientSerialize`

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

Кроме аспекта `ClientAvailableInterface`, `BaseException` так же предлагает такие аспекты:
* `SystemExceptionInterface` - исключение, которое произошло из-за ошибки в системе, например диск переполнен.
* `RuntimeExceptionInterface` - исключение, которое случилось во время работы программы, но не является ошибкой программиста.

Все другие исключения считаются ошибками программиста и не должны быть показаны пользователю.
106 changes: 69 additions & 37 deletions docs/03-BaseException.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,52 +11,66 @@
Наследуемые исключения могут так же прозрачно поддерживать эти режимы, а могут перекрывать их своим конструктором.

Например, класс `UnexpectedValue`, может вести себя как `BaseException`,
если параметр `$name` будет иметь тип отличный от скаляра.
если параметр `$name` будет массивом.

```php
class UnexpectedValue extends LoggableException
/**
* The variable has an unexpected value!
*/
class UnexpectedValue extends LoggableException
{
protected string $template = 'Unexpected value {value} occurred in the variable {name}';

/**
* The variable has an unexpected value!
*
* @param string|array $name Variable name
* or list of parameters for exception
* @param mixed $value Value
* @param string|class-string|null $rules Rules description
*/
public function __construct(array|string $name, mixed $value = null, string|null $rules = null)
{
public function __construct(string|array $name, mixed $value = null, string $rules = null)
{
if(!is_scalar($name))
{
parent::__construct($name);
return;
}

parent::__construct
([
'message' => 'Unexpected value',
'name' => $name,
'value' => self::truncate($value),
'rules' => $rules,
'type' => self::get_value_type($value)
]);
if (!\is_scalar($name)) {
parent::__construct($name);
return;
}

parent::__construct([
'name' => $name,
'value' => $this->toString($value),
'message' => $rules,
'type' => $this->typeInfo($value),
]);
}
}
```

## Шаблоны сообщений

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

Шаблоны сообщений решают данную задачу, определяя текст шаблона ошибки, который формирует сообщение `message`.

Так как базовый класс `\Exception` запрещает переопределять метод `getMessage()`,
шаблон формируется в отдельном свойстве `template` и может быть инициализирован через конструктор `BaseException`.
Однако правилом хорошего тона является определение шаблона в дочернем классе, при помощи переопределения свойства:
Каждое исключение может иметь свой уникальный шаблон сообщения, которые можно определить в свойстве `template`:

```php
class UnexpectedValueType extends LoggableException
{
protected $template = 'Unexpected type occurred for the value {name} and type {type}. Expected {expected}';
```

Шаблон сообщения так же может быть передан в контексте исключения с помощью специального ключа `template`:

```php
$exception = new UnexpectedValueType
([
'template' => 'Custom template {name} {type} {expected}',
'name' => 'test',
'type' => 'string',
'expected' => 'integer'
]);
```

Формат строки шаблона соответствует правилам [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md).

Если исключение определяет шаблон, тогда конструктор `BaseException` работает иначе:
Если исключение определяет шаблон, тогда конструктор `BaseException` работает следующим образом:

1. *Placeholders* шаблона заменяются данными из контекста, и передаются в конструктор `\Exception`.
Таким образом, метод `getMessage()` вернёт полный текст ошибки.
Expand All @@ -78,6 +92,19 @@ class UnexpectedValueType extends LoggableException

```

## Управление журналированием

Класс `BaseException` имеет два флага, которые управляют журналированием:
* `isLoggable` - флаг, указывающий, что исключение должно быть записано в журнал.
* `isFatal` - флаг, указывающий, что исключение является фатальным.

Каким образом эти флажки будут использоваться, зависит от реализации журналирования, однако общие правила таковы:
1. Если не установлен флаг `isLoggable`, то исключение не будет записано в журнал.
2. Если исключение является фатальным, то оно будет записано в журнал.
3. Если исключение не является фатальным, но установлен флаг `isLoggable`, то оно будет записано в журнал.

Фатальные исключения могут быть обработаны особым образом, но это зависит от реализации.

## Наследование

В большинстве случаев дочерний класс переопределяет только конструктор, так как ему нужно сформировать данные исключения.
Expand All @@ -92,7 +119,8 @@ class UnexpectedValueType extends LoggableException
3. Если `BaseException::isLoggable` финализировать исключение.
4. Если `BaseException::isFatal` вызвать обработчик фатальных исключений.

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

Изменение свойств флажков (с префиксом `is`) вызывает изменение в поведении базового конструктора.

Expand Down Expand Up @@ -191,7 +219,7 @@ class UnexpectedValueType extends LoggableException
public function __construct($name, $value = null)
{
// Для журнала отладки сохраним полные данные:
$this->set_debug_data(['value' => $value]);
$this->setDebugData(['value' => $value]);

parent::__construct
([
Expand All @@ -211,9 +239,9 @@ class UnexpectedValueType extends LoggableException
public function __construct($name, $value = null)
{
// Принудительное включение режима отладки
$this->is_debug = true;
$this->isDebug = true;
// Для отладчика сохраним полные данные:
$this->set_debug_data(['value' => $value]);
$this->setDebugData(['value' => $value]);

parent::__construct
([
Expand Down Expand Up @@ -265,10 +293,14 @@ class UnexpectedValueType extends LoggableException

Исключения контейнеры возвращают сериализацию не самих себя, а исключения `previous`.

За общую сериализацию/десериализацию отвечают статические методы:
За общую сериализацию/десериализацию отвечают методы:

- `BaseException::toArray()`;
- `BaseException::arrayToErrors()`.

- `BaseException::errors_to_array()`;
- `BaseException::array_to_errors()`.
Метод arrayToErrors является защищённым, и предназначен для использования в дочерних классах, только в том случае,
если исключение может быть восстановлено из сериализованных данных.
Обычно такие исключения являются DTO объектами, что не является общим случаем.

## Особенности

Expand Down Expand Up @@ -315,11 +347,11 @@ class UnexpectedValueType extends LoggableException
catch(BaseException $e)
{
// out: Test\ZClass->zfun
echo implode('', $exception->get_source());
echo implode('', $exception->getSource());
}
```

Для вычисления источника классов `PHP` `\Exception` используйте метод `BaseException::get_source_for()`.
Для вычисления источника классов `PHP` `\Exception` используйте метод `HelperTrait::getSourceFor()`.

### Определение вложенного исключения

Expand Down
Loading

0 comments on commit 98dabcb

Please sign in to comment.