Паттерн Интерпретатор (Interpreter) в PHP
Короткий скринкаст: паттерн «Интерпретатор» (Interpreter) — грамматика языка выражается деревом объектов, и каждый узел умеет вычислить себя. Строим выражение (5 + 3) * 2 и получаем 16.
Описание
Интерпретатор описывает грамматику языка набором классов и учит каждый узел дерева вычислять себя. Терминальный узел Number хранит готовое значение, а нетерминальные Add и Multiply держат по два вложенных выражения и рекурсивно просят их посчитать. Клиент собирает дерево (5 + 3) * 2 и вызывает interpret() только у корня — дальше вычисление растекается по дереву само. Чтобы добавить новое правило языка, достаточно реализовать Expression ещё одним классом.
UML-диаграмма
Код
Expression.php
interface Expression
{
public function interpret(): int;
}
Number.php
class Number implements Expression
{
public function __construct(private int $value) {}
public function interpret(): int
{
return $this->value;
}
}
Add.php
class Add implements Expression
{
public function __construct(private Expression $left, private Expression $right) {}
public function interpret(): int
{
return $this->left->interpret() + $this->right->interpret();
}
}
Multiply.php
class Multiply implements Expression
{
public function __construct(private Expression $left, private Expression $right) {}
public function interpret(): int
{
return $this->left->interpret() * $this->right->interpret();
}
}
demo.php
require_once 'Expression.php';
require_once 'Number.php';
require_once 'Add.php';
require_once 'Multiply.php';
$add = new Add(new Number(5), new Number(3));
$multiply = new Multiply($add, new Number(2));
echo $multiply->interpret().PHP_EOL;
Пример результата
После php demo.php дерево само вычисляет себя: сложение вложено в умножение, и корневой interpret() возвращает результат (5 + 3) * 2:
16
Преимущества
- Грамматика описывается явными классами, а не разбором строк «на месте».
- Новое правило языка — это просто новое выражение, существующий код не меняется.
- Правила легко комбинировать: любое выражение можно вложить в другое.
- Каждый узел отвечает только за своё правило (принцип единственной обязанности).
Когда использовать
- Когда есть простой язык или нотация, которую нужно интерпретировать: запросы, условия, формулы.
- Когда грамматика невелика и стабильна, а правила удобно выразить классами.
- Когда одно и то же правило нужно переиспользовать внутри других выражений.
- Когда вычисление естественно ложится на дерево объектов с рекурсией.
Использование в Laravel
В Laravel Интерпретатор встречается там, где правило превращается в объект с методом вычисления. Классический пример — правила валидации (Illuminate\Contracts\Validation\Rule и Illuminate\Validation\Rules\*): каждое правило инкапсулирует свою логику и умеет проверить значение. Тот же подход — у Illuminate\Database\Query\Expression и правил БД, а также у фильтров запросов, где набор условий собирается как дерево и вычисляется при построении SQL.