下面小編就為大家帶來一篇老生常談PHP物件導向之解譯器模式。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
最近在看 “深入PHP物件導向模式與實踐” ,學習書中的內容後瞬間覺得自己有點高大上了,哈 ! 其實還是個菜B。相信也會有新手朋友在看這本(我自己也是新手),對書中我個人認為比較難的內容的學習心得就想拿出來分享和交流,1是希望對自己所學知識能夠起到鞏固和加深理解的作用 2是希望對看到本文且感興趣的新手朋友一些協助。
這部分內容看了好幾遍了代碼也跟著敲了幾遍,估計本文想要實現的功能大概就是使用者在web頁面上輸入一些內容,然後通過背景程式解析後進行回複(感覺就是在廢話)。例如我在前台web頁面輸入框裡輸入:
$input = "4";$input equals "4" or $input equals "four";
然後提交,系統就會回複類似 “條件成立” 或者 “條件不成立”的結果(有點類似直接在前台寫代碼並運行,後台解析後會返回一個結果。原書中雖然沒有講解整個前台輸入到後台解析的過程但我猜這個後台解析應該還有一個使用Regex提取類似上面2行代碼中關鍵字的過程)
上面這二行代碼雖然是作者發明的語言,但根據字面含義也不難理解,第一行是定義一個變數並賦值,第二行是對變數進行一個判斷(變數等於4或者等於four)。
廢話不多說來看看這個模式定義的這幾個類 (類圖請自行看原文):
一、interpreterContext 這個類就像一個容器 主要是用來存放和擷取需要進行比較的值和比較的結果的,例如上述代碼中的4, four,和比較結果 “true”或“false”,儲存的形式是數組即類的屬性$expressionstore,代碼如下:
class InterpreterContext{ private $expressionstore = array(); //存放比較的值和結果 function replace(Expression $exp,$value){ // 設定值 $this->expressionstore[$exp->getKey()] = $value; } function lookup(Expression $exp){ //擷取值 return $this->expressionstore[$exp->getKey()]; }}
這個類就像一個工具,供其他類來使用(它和其他類不存在繼承、組合或彙總的關係)。
二、Expression 這是一個運算式的抽象類別,定義了抽象方法interpret() 和方法getKey()
代碼如下:
abstract class Expression { private static $keycount = 0; //計數用的 private $key; //存放一個唯一值 //主要實現將前台擷取到的資料存放到上述InterpreterContext類中的功能,看到下面的內容就會發現繼承他的類調用了InterpreterContext類的replace()方法 abstract function interpret (InterpreterContext $context); //擷取一個唯一值 function getKey(){ if(!isset($this->key)){ self::$keycount++; $this->key= self::$keycount; } return $this->key; }}
下面將要講到的類都將繼承這個類,並且他和OperatorExpression(操作符運算式抽象類別)是一個組合的關係,也就是說OperatorExpression在初始化時可以包含所有繼承了Expression的子類(這也是本書一直在強調的要面向介面編程,這個Expression就是個介面,利用這個介面可以實現多態,不知道自己裝B說的對不對,哈! 具體可以在看看原書的類圖)
三、LiteralExpression 文字運算式類,作用就是將一個字串儲存到InterpreterContext這個小容器裡,儲存成一個索引數組,例如儲存開頭那二句自創代碼中的 4 或者 four
代碼如下:
class LiteralExpression extends Expression{ private $value; function __construct ($value){ //初始化時傳入要儲存的值 $this->value= $value; } function interpret(InterpreterContext $context){ //調用InterpreterContext類的replace()將$value儲存到InterpreterContext這個小容器裡 $context->replace($this,$this->value); }}
四、VariableExpression Variant 運算式類,和上面類的作用是一樣的只不過資料將被儲存成關聯陣列,關聯陣列中的健是變數名,值呢就是變數的值,例如開頭二句中的變數"input" 和值 "4",
代碼如下:
class VariableExpression extends Expression{ private $name; //變數名 private $val; //變數值 function __construct ($name,$val=null){ $this->name = $name; $this->val = $val; } function interpret(InterpreterContext $context){ if(!is_null($this->val)){ $context->replace($this,$this->val); $this->val = null; } } function setValue($value){ //用於設定變數的值 $this->val = $value; } function getKey(){ //這個複寫了父類的getKey()方法,在小容器InterpreterContext的lookup()方法調用這個類的執行個體的getKey()方法時 它將返回一個字串(即變數名)而不是數字索引 return $this->name; }}
五、OperatorExpression 操作符運算式抽象基類,此類繼承且組合了Expression抽象基類,實現的interpret()方法主要儲存運算式的計算結果
代碼如下:
abstract class OperatorExpression extends Expression{protected $l_op; //運算式左邊的值protected $r_op; //運算式右邊的值function __construct (Expression $l_op,Expression $r_op){ //初始化時可組合繼承了Expression類的子類執行個體$this->l_op = $l_op;$this->r_op = $r_op;}function interpret(InterpreterContext $context){ //主要用於儲存表達試的結果(儲存到InterpreterContext 類的執行個體中)$this->l_op->interpret($context); //將Expression子類執行個體的值或計算結果儲存到InterpreterContext 類的執行個體中$this->r_op->interpret($context);$result_l = $context->lookup($this->l_op); //擷取上一步的值或計算結果$result_r = $context->lookup($this->r_op);$this->doInterpret($context,$result_l,$result_r); //具體的比較運算由繼承的子類來實現}protected abstract function doInterpret(InterpreterContext $context,$result_l,$result_r);}
六、EqualsExpression、BooleanOrExpression、BooleanAndExpression,分別為繼承了OperatorExpression 抽象基類的相等運算式、或運算式、與運算式只有一個方法doInterpret()內部調用了InterpreterContext類的replace()方法將運算式的計算結果儲存到InterpreterContext類的執行個體中
代碼如下:
//相等運算式class EqualsExpression extends OperatorExpression {protected function doInterpret(InterpreterContext $context,$result_l,$result_r){$context->replace($this,$result_l == $result_r);}}//或運算式class BooleanOrExpression extends OperatorExpression{protected function doInterpret(InterpreterContext $context,$result_l,$result_r){$context->replace($this,$result_l || $result_r);}}//與運算式class BooleanAndExpression extends OperatorExpression{protected function doInterpret(InterpreterContext $context,$result_l,$result_r){$context->replace($this,$result_l && $result_r);}}
到此為止此模式相關的類就介紹完畢,上述代碼都是進過測試的,可直接複製粘貼運行來查看結果,現在我們就來看看用戶端代碼:
用戶端代碼一:
$context = new InterpreterContext();$statement = new BooleanOrExpression ( //可嘗試將此操作符運算式換成BooleanAndExpression 運行一下 看看執行結果//可嘗試將LiteralExpression中執行個體化的參數改成其他值看看運算結果,或者直接將EqualsExpression對象換成BooleanOrExpression 或BooleanAndExpression new EqualsExpression(new LiteralExpression('four'),new LiteralExpression('four')), new EqualsExpression(new LiteralExpression('b'),new LiteralExpression('4')));$statement->interpret($context);if($context->lookup($statement)){echo '條件成立';} else {echo '條件不成立';}
用戶端代碼二:
$context = new InterpreterContext();$statement = new BooleanOrExpression(new BooleanAndExpression(new EqualsExpression(new LiteralExpression('4'),new LiteralExpression('4')),new EqualsExpression(new LiteralExpression('4'),new LiteralExpression('4'))),new EqualsExpression(new LiteralExpression('b'),new LiteralExpression('4')));$statement->interpret($context);if($context->lookup($statement)){echo '條件成立';} else {echo '條件不成立';}
用戶端代碼三:
這是原文的用戶端代碼執行個體和上述用戶端代碼的區別在於使用了Variant 運算式VariableExpression
$context = new InterpreterContext(); $input = new VariableExpression('input'); //這裡定義了一個變數input 但並未賦值$statement = new BooleanOrExpression(new EqualsExpression($input,new LiteralExpression('four')), //這裡Variant 運算式和文字運算式的值將進行一個是否相等的比較new EqualsExpression($input,new LiteralExpression('4')));foreach (array("four","4","52") as $val){$input->setValue($val); //對input這個變數賦值print "變數input的值為:$val:<br/>";$statement->interpret($context); //進行比較並將比較結果存入InterpreterContext對象執行個體if($context->lookup($statement)){ //擷取比較的結果print "條件成立 <br/>";} else {print "條件不成立 <br/>";}}
上述代碼經過測試都可以正常運行,有需要的朋友可以複製下來,運行一下看看結果。