老生常谈PHP面向对象之解释器模式


Posted in PHP onMay 17, 2017

最近在看 “深入PHP面向对象模式与实践” ,学习书中的内容后瞬间觉得自己有点高大上了,哈 ! 其实还是个菜B。相信也会有新手朋友在看这本(我自己也是新手),对书中我个人认为比较难的内容的学习心得就想拿出来分享和交流,1是希望对自己所学知识能够起到巩固和加深理解的作用 2是希望对看到本文且感兴趣的新手朋友一些帮助。

这部分内容看了好几遍了代码也跟着敲了几遍,估计本文想要实现的功能大概就是用户在web页面上输入一些内容,然后通过后台程序解析后进行回复(感觉就是在废话)。例如我在前台web页面输入框里输入:

$input = "4";
$input equals "4" or $input equals "four";

然后提交,系统就会回复类似 “条件成立” 或者 “条件不成立”的结果(有点类似直接在前台写代码并运行,后台解析后会返回一个结果。原书中虽然没有讲解整个前台输入到后台解析的过程但我猜这个后台解析应该还有一个使用正则表达式提取类似上面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 变量表达式类,和上面类的作用是一样的只不过数据将被保存成关联数组,关联数组中的健是变量名,值呢就是变量的值,例如开头二句中的变量"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 '条件不成立';
}

客户端代码三:

这是原文的客户端代码实例和上述客户端代码的区别在于使用了变量表达式VariableExpression

$context = new InterpreterContext();
$input = new VariableExpression('input');//这里定义了一个变量input 但并未赋值

$statement = new BooleanOrExpression(
new EqualsExpression($input,new LiteralExpression('four')),//这里变量表达式和文字表达式的值将进行一个是否相等的比较
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/>";
}
}

上述代码经过测试都可以正常运行,有需要的朋友可以复制下来,运行一下看看结果。

以上这篇老生常谈PHP面向对象之解释器模式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP编程与应用
Oct 09 PHP
一个PHP日历程序
Dec 06 PHP
echo, print, printf 和 sprintf 区别
Dec 06 PHP
php&amp;mysql 日期操作小记
Feb 27 PHP
win7下memCache的安装过程(具体操作步骤)
Jun 28 PHP
深入理解PHP中的Streams工具
Jul 03 PHP
PHP使用反射机制实现查找类和方法的所在位置
Apr 22 PHP
yii2中关于加密解密的那些事儿
Jun 12 PHP
PHP输出Excel PHPExcel的方法
Jul 26 PHP
PHP实现的用户注册表单验证功能简单示例
Feb 25 PHP
laradock环境docker-compose操作详解
Jul 29 PHP
PHP实现笛卡尔积算法的实例讲解
Dec 22 PHP
phpmyadmin下载、安装、配置教程
May 16 #PHP
Windows下php+mysql5.7配置教程
May 16 #PHP
php使用curl实现ftp文件下载功能
May 16 #PHP
PHP jpgraph库的配置及生成统计图表:折线图、柱状图、饼状图
May 15 #PHP
php使用curl实现简单模拟提交表单功能
May 15 #PHP
PHP读取Excel类文件
May 15 #PHP
详谈php中 strtr 和 str_replace 的效率问题
May 14 #PHP
You might like
PHP使用mysql_fetch_row查询获得数据行列表的方法
2015/03/18 PHP
JavaScript 组件之旅(二)编码实现和算法
2009/10/28 Javascript
基于jQuery的固定表格头部的代码(IE6,7,8测试通过)
2010/05/18 Javascript
jQuery读取和设定KindEditor值的方法
2013/11/22 Javascript
js浮点数保留两位小数点示例代码(四舍五入)
2013/12/26 Javascript
多选列表框动态添加,移动,删除,全选等操作的简单实例
2014/01/13 Javascript
JavaScript控制网页层收起和展开效果的方法
2015/04/15 Javascript
JavaScript如何实现组合列表框中元素移动效果
2016/03/01 Javascript
jquery中实现时间戳与日期相互转换
2016/04/12 Javascript
js判断手机浏览器操作系统和微信浏览器的方法
2016/04/30 Javascript
实例讲解JavaScript中instanceof运算符的用法
2016/06/08 Javascript
jQuery EasyUI提交表单验证
2016/07/19 Javascript
全面了解构造函数继承关键apply call
2016/07/26 Javascript
微信小程序 数据绑定详解及实例
2016/10/25 Javascript
Javascript 实现匿名递归的实例代码
2017/05/25 Javascript
详解webpack的配置文件entry与output
2017/08/21 Javascript
js屏蔽退格键(backspace或者叫后退键与F5)
2019/02/10 Javascript
详解小程序中h5页面onShow实现及跨页面通信方案
2019/05/30 Javascript
关于NodeJS中的循环引用详解
2019/07/23 NodeJs
vue 取出v-for循环中的index值实例
2019/11/09 Javascript
JavaScript定时器使用方法详解
2020/03/26 Javascript
[05:53]敌法师的金色冠名ID"BurNIng",是传说,是荣耀
2020/07/11 DOTA
[02:49:21]2019完美盛典全程录像
2019/12/08 DOTA
Python建立Map写Excel表实例解析
2018/01/17 Python
特征脸(Eigenface)理论基础之PCA主成分分析法
2018/03/13 Python
django框架之cookie/session的使用示例(小结)
2018/10/15 Python
python使用threading.Condition交替打印两个字符
2019/05/07 Python
Django 拆分model和view的实现方法
2019/08/16 Python
详解Python实现进度条的4种方式
2020/01/15 Python
基于Python的接口自动化读写excel文件的方法
2021/01/15 Python
详解如何修改jupyter notebook的默认目录和默认浏览器
2021/01/24 Python
班队活动设计方案
2014/01/30 职场文书
羽毛球比赛策划方案
2014/06/13 职场文书
2014年计划生育协会工作总结
2014/11/14 职场文书
师德师风事迹材料
2014/12/20 职场文书
爱心捐赠活动简讯
2015/07/20 职场文书