PHP Interpreter Pattern
A short screencast: the Interpreter pattern — a language grammar is expressed as a tree of objects, and every node can evaluate itself. We build the expression (5 + 3) * 2 and get 16.
Overview
The Interpreter describes a language grammar with a set of classes and teaches every node of the tree to evaluate itself. A terminal node, Number, stores a ready value, while the non-terminal Add and Multiply hold two nested expressions and recursively ask them to compute. The client builds the tree (5 + 3) * 2 and calls interpret() only on the root — the evaluation then flows through the tree by itself. To add a new grammar rule it is enough to implement Expression with one more class.
UML diagram
Code
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;
Example output
After php demo.php the tree evaluates itself: the addition is nested inside the multiplication, and the root interpret() returns the result of (5 + 3) * 2:
16
Advantages
- The grammar is described with explicit classes instead of ad-hoc string parsing.
- A new grammar rule is just a new expression; existing code does not change.
- Rules compose easily: any expression can be nested inside another.
- Each node is responsible only for its own rule (single responsibility principle).
When to use
- When there is a small language or notation to interpret: queries, conditions, formulas.
- When the grammar is small and stable and its rules map neatly to classes.
- When the same rule must be reused inside other expressions.
- When evaluation naturally maps to a tree of objects with recursion.
Usage in Laravel
In Laravel the Interpreter shows up wherever a rule becomes an object with an evaluation method. The classic example is validation rules (Illuminate\Contracts\Validation\Rule and Illuminate\Validation\Rules\*): each rule encapsulates its own logic and can validate a value. The same approach is used by Illuminate\Database\Query\Expression and database rules, and by query filters, where a set of conditions is assembled as a tree and evaluated when the SQL is built.