?解釋器的概念其實很好理解,假如你女朋友問你你在干嘛呀,這個時候她往往是想你了。奇怪,我們獲取到的信息明明是“你在干嘛呀”,但是經過“解釋器“處理之后,就變成了“我想你了”。這下子好理解了吧,基于這個特點,解釋器模式可以構造一個可以用于創建腳本化應用的迷你語言解釋器。
那么解釋器模式到底有什么用呢?
假設現在我們做的是一個問卷調查平臺,命題人可以通過我們的平臺來設計問卷以及問卷答案。為了檢測用戶輸入的數據中是否包含答案,我們知道可以用php的正則表達式來實現,但是,一般命題人或許并不會正則表達式,所以為了方便命題人使用我們的系統,假如我們現在有一套更加容易理解的迷你語言用來設置答案,那么就能大大地提高用戶體驗。話不多說,讓我們來看看具體是怎么實現的(以下只展示解釋器部分,實際上還需要解析器部分)
現在我們 的迷你語言中包含這些語法元素,變量,字符串,and(與),equals(相等判斷).
首先我們定義一個數據存儲類,用來存放于表達式對象相關的數據
一個表達式的組成既有操作數,也有操作符。先定義一個表達式抽象基類
在interpret方法中傳入interpreterContext對象是因為在對表達式對象的解釋過程中會涉及對象的存取,可以看出表達式類是依賴于interpreterContext類的。接下來定義字符串表達式類和變量表達式類,在變量表達式類中我們使用變量名作為變量表達式對象的索引,所以需要對原先抽象父類expression中的getKey方法進行重寫,同時也增加了setValue方法用于修改變量值。代碼如下:
class ?variableExpression extends expression{
? ? ? ? ? ? ? ? ? ? ? ? ? ? public $name;//變量名
? ? ? ? ? ? ? ? ? ? ? ? ? ? public $value=null;//變量值
? ? ? ? ? ? ? ? ? ? ? ? ? ? public function __construct($name,$value){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?$this->name=$name;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?$this->value=$value;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}?
? ? ? ? ? ? ? ? ? ? ? ? ? ? public function getKey()
? ? ? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return $this->name;
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ?public function ?setValue($value){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?$this->value=$value;
? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? public function interpret(intepreterContext$context)
? ? ? ? ? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if(!is_null($this->value)) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? $context->insert($this, $this->value);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? $this->value=null;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
}
還有一點需要注意的,就是在interpret方法中插入變量名和變量值后,將該變量對象的value置空,因為如果后期定義了變量名相同的變量,則在存儲空間中該變量名索引所對應的變量值會被更新,如果這里我們沒有把已經存儲到存儲空間的變量對象的變量值屬性置空,則后期如果不小心再次調用了該變量對象的interpret方法就會修改當前值,這樣顯然是不行的。
接下來定義字符串表達式:
這里字符串對象在存儲空間的索引我們采用默認的方式。
到這里我們先來簡單總結一下,可以看出操作數對象的解釋主要是將與操作數對象相關聯的數據放入存儲空間,同時為設置索引以便引用。
而對于操作符對象,我們可以將操作符對象理解為一個組合對象(二元操作符的話需要包含兩個表達式對象,注意表達式對象可以是操作符對象也可以是操作數對象)。因此,我們定義了一個抽象操作符基類。
有了該操作符抽象基類,我們就可以來定義具體的操作符類了。
下面來演示一下用法,
問題:我和你媽媽掉進水里你救誰
答案:你和媽媽。
為了設置答應,我們可以這樣來使用這個迷你語言,假設input是輸入,那么我們寫出來的語句大概是這樣子。input1 equals '你' and input2 equals '媽媽',忽略對語句進行解析的部分,我們直接跳都解釋器部分。代碼如下:
直到實例化了and操作符對象,我們這時候已經通過傳遞對象的方式成功構建了一個表達式樹,兩個equals對象分別包含了一個變量對象和一字符串對象,然后最頂層的And對象包含了兩個equals對象。當調用and對象的解釋方法時,便會隱式地調用其包含對象的解釋方法,最終將and操作結果和and對象的索引寫入存儲空間。在var_dump之后便可得到一個true。
好了,以上便是解釋器模式的基本介紹,由于水平有限未免有不當之處,歡迎指出,希望大家多多鼓勵,謝謝~~