我有一个包含三类对象的解析器:解析器本身、Token
s和State
s。 解析器从词法分析器生成令牌。 一切都是黑盒的,因此令牌对解析器状态或解析器一无所知,状态对令牌一无所知。 一个相当简单的安排版本:
class Parser {
public function parse() {
$this->state = new StEmpty;
while ($token = $this->lexer->get()) {
$this->state = $this->token->expect($this);
}
}
public function stateStart() {
return $this->state->stateStart();
}
}
class StartToken {
public function expect(Parser $parser) {
return $parser->stateStart();
}
}
class StEmpty {
public function stateStart() {
return new StStart;
}
}
我遇到的问题是,有时当状态发生变化时,解析器需要采取一些操作(例如在到达结束规则令牌时向树添加规则)。 只有State
知道这一点,所以由状态来告诉解析器该怎么做。 问题是将Parser
带到State
。 我可以在状态构造函数中注入Parser
,但并非每个State
都需要解析器,这会导致大量重复代码(除非我有一个 State
s 的基类并且 Parser
是受保护的成员,但我想避免扩展任何内容)。 我也可以在需要它state
方法中注入Parser
,但我有一个类似的问题:这将是大量的重复,并且并非所有State
实现都需要给定方法的解析器。
所以我的问题是,我怎样才能让State
在需要时了解Parser
,而不会产生不必要的继承或代码重复? 如果我需要另一个完全可以接受的课程。
如果这很难理解,这里有一个"解开"的版本:
class Parser {
public function parse() {
$this->state = 'StEmpty';
while ($token = $this->lexer->get()) {
switch ($token) {
case 'StartToken':
switch ($this->state) {
case 'StEmpty':
$this->state = 'StStart';
break;
}
break;
}
}
}
}
这个问题的答案也适用于其他语言,但我知道这在允许重载的语言中更容易做到。 PHP没有。
PHP 5.4 引入了以下特性: http://php.net/manual/en/language.oop5.traits.php
也许你可以使用特征作为遗传和注入之间的中间部分。