3

Tokenパーサー自体、 s、およびs の3 つのクラスのオブジェクトを持つパーサーがありますState。パーサーはレクサーからトークンを生成します。すべてがブラック ボックス化されているため、トークンはパーサーの状態やパーサーについて何も知らず、状態もトークンについて何も知りません。配置のかなり単純なバージョン:

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がパーサーを必要とするわけではなく、多くの重複コードが発生します ( States の基本クラスParserがあり、保護されたメンバーである場合を除きますが、何かを拡張することは避けたいと考えています)。 )。必要なメソッドに を注入することもできParserますが、同様の問題があります。stateState実装には、特定のメソッドのパーサーが必要です。

だから私の質問は、不必要な継承やコードの重複なしに、いつ必要な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 はそうではありません。

4

1 に答える 1

1

PHP 5.4 では特性が導入されています: http://php.net/manual/en/language.oop5.traits.php

おそらく、継承と注入の中間としてトレイトを使用できます。

于 2012-05-07T04:38:22.503 に答える