PHP设计模式访问者与解释器实现访问者模式和解释器模式属于行为型设计模式。访问者可以在不修改类的情况下为类增加操作解释器定义语言的语法并解释执行。今天说说这两种模式的PHP实现。访问者模式的核心是双重分派。元素类接受访问者访问者根据元素类型执行不同的操作。php// 元素接口interface Element{public function accept(Visitor $visitor): void;}// 具体元素class Book implements Element{public function __construct(public string $title,public string $author,public float $price) {}public function accept(Visitor $visitor): void{$visitor-visitBook($this);}}class Electronics implements Element{public function __construct(public string $name,public string $brand,public float $price,public int $warrantyMonths) {}public function accept(Visitor $visitor): void{$visitor-visitElectronics($this);}}class Clothing implements Element{public function __construct(public string $name,public string $size,public string $material,public float $price) {}public function accept(Visitor $visitor): void{$visitor-visitClothing($this);}}// 访问者接口interface Visitor{public function visitBook(Book $book): void;public function visitElectronics(Electronics $electronics): void;public function visitClothing(Clothing $clothing): void;}// 具体访问者1价格计算class PriceCalculator implements Visitor{private float $total 0;public function visitBook(Book $book): void{$this-total $book-price;echo 书籍: {$book-title} - {$book-price}元\n;}public function visitElectronics(Electronics $electronics): void{$this-total $electronics-price;echo 电子产品: {$electronics-name} - {$electronics-price}元\n;}public function visitClothing(Clothing $clothing): void{$this-total $clothing-price;echo 服装: {$clothing-name} - {$clothing-price}元\n;}public function getTotal(): float{return $this-total;}}// 具体访问者2XML生成class XmlExporter implements Visitor{private array $items [];public function visitBook(Book $book): void{$this-items[] [type book,title $book-title,author $book-author,price $book-price,];}public function visitElectronics(Electronics $electronics): void{$this-items[] [type electronics,name $electronics-name,brand $electronics-brand,price $electronics-price,warranty $electronics-warrantyMonths,];}public function visitClothing(Clothing $clothing): void{$this-items[] [type clothing,name $clothing-name,size $clothing-size,price $clothing-price,];}public function getXml(): string{$doc new DOMDocument(1.0, UTF-8);$doc-formatOutput true;$root $doc-createElement(items);foreach ($this-items as $item) {$element $doc-createElement(item);foreach ($item as $key $value) {$child $doc-createElement($key, (string)$value);$element-appendChild($child);}$root-appendChild($element);}$doc-appendChild($root);return $doc-saveXML();}}// 具体访问者3折扣应用class DiscountApplier implements Visitor{public function visitBook(Book $book): void{// 书籍不打折echo 书籍: {$book-title} - 无折扣\n;}public function visitElectronics(Electronics $electronics): void{$discount $electronics-price * 0.1;echo 电子产品: {$electronics-name} - 折扣{$discount}元\n;}public function visitClothing(Clothing $clothing): void{$discount match ($clothing-material) {丝绸 $clothing-price * 0.2,羊毛 $clothing-price * 0.15,default $clothing-price * 0.05,};echo 服装: {$clothing-name} - 折扣{$discount}元\n;}}$items [new Book(PHP设计模式, 张三, 69.9),new Electronics(智能手机, TechBrand, 3999.0, 12),new Clothing(T恤, M, 棉, 129.0),];echo 价格计算 \n;$calculator new PriceCalculator();foreach ($items as $item) $item-accept($calculator);echo 总计: {$calculator-getTotal()}元\n;echo \n 折扣应用 \n;$discount new DiscountApplier();foreach ($items as $item) $item-accept($discount);?解释器模式用于定义语言的语法并解释执行。phpinterface Expression{public function interpret(array $context): int;}class NumberExpression implements Expression{public function __construct(private int $number) {}public function interpret(array $context): int{return $this-number;}}class VariableExpression implements Expression{public function __construct(private string $name) {}public function interpret(array $context): int{if (!isset($context[$this-name])) {throw new RuntimeException(未定义的变量: {$this-name});}return $context[$this-name];}}class AddExpression implements Expression{public function __construct(private Expression $left,private Expression $right) {}public function interpret(array $context): int{return $this-left-interpret($context) $this-right-interpret($context);}}class SubtractExpression implements Expression{public function __construct(private Expression $left,private Expression $right) {}public function interpret(array $context): int{return $this-left-interpret($context) - $this-right-interpret($context);}}class MultiplyExpression implements Expression{public function __construct(private Expression $left,private Expression $right) {}public function interpret(array $context): int{return $this-left-interpret($context) * $this-right-interpret($context);}}class Parser{private array $tokens;private int $pos 0;public function __construct(string $expression){// 简单的词法分析$expression str_replace( , , $expression);$this-tokens [];$currentNum ;for ($i 0; $i strlen($expression); $i) {$char $expression[$i];if (ctype_digit($char)) {$currentNum . $char;} else {if ($currentNum ! ) {$this-tokens[] [type num, value (int)$currentNum];$currentNum ;}if (ctype_alpha($char)) {$varName ;while ($i strlen($expression) ctype_alpha($expression[$i])) {$varName . $expression[$i];$i;}$i--;$this-tokens[] [type var, value $varName];} elseif (in_array($char, [, -, *, (, )])) {$this-tokens[] [type op, value $char];}}}if ($currentNum ! ) {$this-tokens[] [type num, value (int)$currentNum];}}public function parse(): Expression{return $this-parseAddSubtract();}private function parseAddSubtract(): Expression{$left $this-parseMultiply();while ($this-pos count($this-tokens) $this-tokens[$this-pos][type] op in_array($this-tokens[$this-pos][value], [, -])) {$op $this-tokens[$this-pos][value];$this-pos;$right $this-parseMultiply();$left $op ? new AddExpression($left, $right): new SubtractExpression($left, $right);}return $left;}private function parseMultiply(): Expression{$left $this-parsePrimary();while ($this-pos count($this-tokens) $this-tokens[$this-pos][type] op $this-tokens[$this-pos][value] *) {$this-pos;$right $this-parsePrimary();$left new MultiplyExpression($left, $right);}return $left;}private function parsePrimary(): Expression{if ($this-pos count($this-tokens)) {throw new RuntimeException(意外的表达式结尾);}$token $this-tokens[$this-pos];if ($token[type] num) {$this-pos;return new NumberExpression($token[value]);}if ($token[type] var) {$this-pos;return new VariableExpression($token[value]);}if ($token[type] op $token[value] () {$this-pos;$expr $this-parseAddSubtract();if ($this-pos count($this-tokens) ||$this-tokens[$this-pos][type] ! op ||$this-tokens[$this-pos][value] ! )) {throw new RuntimeException(缺少右括号);}$this-pos;return $expr;}throw new RuntimeException(意外的token: . json_encode($token));}}// 使用解释器$expressions [10 20,x y * 2,(a b) * c,];foreach ($expressions as $exprStr) {try {$parser new Parser($exprStr);$ast $parser-parse();$context [x 5, y 10, a 3, b 4, c 2];$result $ast-interpret($context);echo {$exprStr} {$result}\n;} catch (Exception $e) {echo {$exprStr} 解析错误: {$e-getMessage()}\n;}}?访问者模式适合数据结构稳定但操作经常变化的场景。解释器模式适合实现简单的领域特定语言。两种模式都适合特定场景不要为了用模式而用模式。
PHP设计模式访问者与解释器实现
发布时间:2026/6/2 6:03:02
PHP设计模式访问者与解释器实现访问者模式和解释器模式属于行为型设计模式。访问者可以在不修改类的情况下为类增加操作解释器定义语言的语法并解释执行。今天说说这两种模式的PHP实现。访问者模式的核心是双重分派。元素类接受访问者访问者根据元素类型执行不同的操作。php// 元素接口interface Element{public function accept(Visitor $visitor): void;}// 具体元素class Book implements Element{public function __construct(public string $title,public string $author,public float $price) {}public function accept(Visitor $visitor): void{$visitor-visitBook($this);}}class Electronics implements Element{public function __construct(public string $name,public string $brand,public float $price,public int $warrantyMonths) {}public function accept(Visitor $visitor): void{$visitor-visitElectronics($this);}}class Clothing implements Element{public function __construct(public string $name,public string $size,public string $material,public float $price) {}public function accept(Visitor $visitor): void{$visitor-visitClothing($this);}}// 访问者接口interface Visitor{public function visitBook(Book $book): void;public function visitElectronics(Electronics $electronics): void;public function visitClothing(Clothing $clothing): void;}// 具体访问者1价格计算class PriceCalculator implements Visitor{private float $total 0;public function visitBook(Book $book): void{$this-total $book-price;echo 书籍: {$book-title} - {$book-price}元\n;}public function visitElectronics(Electronics $electronics): void{$this-total $electronics-price;echo 电子产品: {$electronics-name} - {$electronics-price}元\n;}public function visitClothing(Clothing $clothing): void{$this-total $clothing-price;echo 服装: {$clothing-name} - {$clothing-price}元\n;}public function getTotal(): float{return $this-total;}}// 具体访问者2XML生成class XmlExporter implements Visitor{private array $items [];public function visitBook(Book $book): void{$this-items[] [type book,title $book-title,author $book-author,price $book-price,];}public function visitElectronics(Electronics $electronics): void{$this-items[] [type electronics,name $electronics-name,brand $electronics-brand,price $electronics-price,warranty $electronics-warrantyMonths,];}public function visitClothing(Clothing $clothing): void{$this-items[] [type clothing,name $clothing-name,size $clothing-size,price $clothing-price,];}public function getXml(): string{$doc new DOMDocument(1.0, UTF-8);$doc-formatOutput true;$root $doc-createElement(items);foreach ($this-items as $item) {$element $doc-createElement(item);foreach ($item as $key $value) {$child $doc-createElement($key, (string)$value);$element-appendChild($child);}$root-appendChild($element);}$doc-appendChild($root);return $doc-saveXML();}}// 具体访问者3折扣应用class DiscountApplier implements Visitor{public function visitBook(Book $book): void{// 书籍不打折echo 书籍: {$book-title} - 无折扣\n;}public function visitElectronics(Electronics $electronics): void{$discount $electronics-price * 0.1;echo 电子产品: {$electronics-name} - 折扣{$discount}元\n;}public function visitClothing(Clothing $clothing): void{$discount match ($clothing-material) {丝绸 $clothing-price * 0.2,羊毛 $clothing-price * 0.15,default $clothing-price * 0.05,};echo 服装: {$clothing-name} - 折扣{$discount}元\n;}}$items [new Book(PHP设计模式, 张三, 69.9),new Electronics(智能手机, TechBrand, 3999.0, 12),new Clothing(T恤, M, 棉, 129.0),];echo 价格计算 \n;$calculator new PriceCalculator();foreach ($items as $item) $item-accept($calculator);echo 总计: {$calculator-getTotal()}元\n;echo \n 折扣应用 \n;$discount new DiscountApplier();foreach ($items as $item) $item-accept($discount);?解释器模式用于定义语言的语法并解释执行。phpinterface Expression{public function interpret(array $context): int;}class NumberExpression implements Expression{public function __construct(private int $number) {}public function interpret(array $context): int{return $this-number;}}class VariableExpression implements Expression{public function __construct(private string $name) {}public function interpret(array $context): int{if (!isset($context[$this-name])) {throw new RuntimeException(未定义的变量: {$this-name});}return $context[$this-name];}}class AddExpression implements Expression{public function __construct(private Expression $left,private Expression $right) {}public function interpret(array $context): int{return $this-left-interpret($context) $this-right-interpret($context);}}class SubtractExpression implements Expression{public function __construct(private Expression $left,private Expression $right) {}public function interpret(array $context): int{return $this-left-interpret($context) - $this-right-interpret($context);}}class MultiplyExpression implements Expression{public function __construct(private Expression $left,private Expression $right) {}public function interpret(array $context): int{return $this-left-interpret($context) * $this-right-interpret($context);}}class Parser{private array $tokens;private int $pos 0;public function __construct(string $expression){// 简单的词法分析$expression str_replace( , , $expression);$this-tokens [];$currentNum ;for ($i 0; $i strlen($expression); $i) {$char $expression[$i];if (ctype_digit($char)) {$currentNum . $char;} else {if ($currentNum ! ) {$this-tokens[] [type num, value (int)$currentNum];$currentNum ;}if (ctype_alpha($char)) {$varName ;while ($i strlen($expression) ctype_alpha($expression[$i])) {$varName . $expression[$i];$i;}$i--;$this-tokens[] [type var, value $varName];} elseif (in_array($char, [, -, *, (, )])) {$this-tokens[] [type op, value $char];}}}if ($currentNum ! ) {$this-tokens[] [type num, value (int)$currentNum];}}public function parse(): Expression{return $this-parseAddSubtract();}private function parseAddSubtract(): Expression{$left $this-parseMultiply();while ($this-pos count($this-tokens) $this-tokens[$this-pos][type] op in_array($this-tokens[$this-pos][value], [, -])) {$op $this-tokens[$this-pos][value];$this-pos;$right $this-parseMultiply();$left $op ? new AddExpression($left, $right): new SubtractExpression($left, $right);}return $left;}private function parseMultiply(): Expression{$left $this-parsePrimary();while ($this-pos count($this-tokens) $this-tokens[$this-pos][type] op $this-tokens[$this-pos][value] *) {$this-pos;$right $this-parsePrimary();$left new MultiplyExpression($left, $right);}return $left;}private function parsePrimary(): Expression{if ($this-pos count($this-tokens)) {throw new RuntimeException(意外的表达式结尾);}$token $this-tokens[$this-pos];if ($token[type] num) {$this-pos;return new NumberExpression($token[value]);}if ($token[type] var) {$this-pos;return new VariableExpression($token[value]);}if ($token[type] op $token[value] () {$this-pos;$expr $this-parseAddSubtract();if ($this-pos count($this-tokens) ||$this-tokens[$this-pos][type] ! op ||$this-tokens[$this-pos][value] ! )) {throw new RuntimeException(缺少右括号);}$this-pos;return $expr;}throw new RuntimeException(意外的token: . json_encode($token));}}// 使用解释器$expressions [10 20,x y * 2,(a b) * c,];foreach ($expressions as $exprStr) {try {$parser new Parser($exprStr);$ast $parser-parse();$context [x 5, y 10, a 3, b 4, c 2];$result $ast-interpret($context);echo {$exprStr} {$result}\n;} catch (Exception $e) {echo {$exprStr} 解析错误: {$e-getMessage()}\n;}}?访问者模式适合数据结构稳定但操作经常变化的场景。解释器模式适合实现简单的领域特定语言。两种模式都适合特定场景不要为了用模式而用模式。