老生常谈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 相关文章推荐
使用MaxMind 根据IP地址对访问者定位
Oct 09 PHP
[转帖]PHP世纪万年历
Dec 06 PHP
php中的实现trim函数代码
Mar 19 PHP
php自动加载的两种实现方法
Jun 21 PHP
php explode函数实例代码
Feb 27 PHP
ThinkPHP实现事务回滚示例代码
Jun 23 PHP
php中单个数据库字段多列显示(单字段分页、横向输出)
Jul 28 PHP
PHP+shell实现多线程的方法
Jul 01 PHP
WIFI万能钥匙密码查询接口实例
Sep 28 PHP
分享五个PHP7性能优化提升技巧
Dec 07 PHP
教你在header中隐藏php的版本信息
Aug 10 PHP
php车辆违章查询数据示例
Oct 14 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实现扫描二维码根据浏览器类型访问不同下载地址
2014/10/15 PHP
php精确的统计在线人数的方法
2015/10/21 PHP
深入php内核之php in array
2015/11/10 PHP
php 截取GBK文档某个位置开始的n个字符方法
2017/03/08 PHP
ASP.NET jQuery 实例9  通过控件hyperlink实现返回顶部效果
2012/02/03 Javascript
js模仿html5 placeholder适应于不支持的浏览器
2013/01/13 Javascript
一个JavaScript递归实现反转数组字符串的实例
2014/10/14 Javascript
Node.js开发之访问Redis数据库教程
2015/01/14 Javascript
微信小程序 图片等比例缩放(图片自适应屏幕)
2016/11/16 Javascript
js实现无缝滚动图(可控制当前滚动的方向)
2017/02/22 Javascript
利用JS判断客户端类型你应该知道的四种方法
2017/12/22 Javascript
js+css实现打字效果
2020/06/24 Javascript
TypeScript开发Node.js程序的方法
2019/04/30 Javascript
js中arguments对象的深入理解
2019/05/14 Javascript
微信小程序上传图片并等比列压缩到指定大小的实例代码
2019/10/24 Javascript
Node配合WebSocket做多文件下载以及进度回传
2019/11/07 Javascript
谈谈我在vue-cli3中用预渲染遇到的坑
2020/04/22 Javascript
微信小程序scroll-view实现滚动到锚点左侧导航栏点餐功能(点击种类,滚动到锚点)
2020/06/11 Javascript
详解React路由传参方法汇总记录
2020/11/29 Javascript
Python列表推导式的使用方法
2013/11/21 Python
Python写的一个简单监控系统
2015/06/19 Python
解决Python下imread,imwrite不支持中文的问题
2018/12/05 Python
Python列表(List)知识点总结
2019/02/18 Python
TensorFlow车牌识别完整版代码(含车牌数据集)
2019/08/05 Python
python opencv圆、椭圆与任意多边形的绘制实例详解
2020/02/06 Python
Python使用monkey.patch_all()解决协程阻塞问题
2020/04/15 Python
Python pexpect模块及shell脚本except原理解析
2020/08/03 Python
python中判断数字是否为质数的实例讲解
2020/12/06 Python
学生党员思想汇报
2013/12/28 职场文书
会计专业自我鉴定
2014/02/10 职场文书
入职担保书怎么写
2014/05/12 职场文书
公务员政审单位鉴定材料
2014/05/16 职场文书
计划生育证明格式及范本
2014/10/09 职场文书
2014年终个人总结报告
2015/03/09 职场文书
铁人观后感
2015/06/16 职场文书
Docker部署Mysql8的实现步骤
2022/07/07 Servers