老生常谈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日历程序
Dec 06 PHP
php cache类代码(php数据缓存类)
Apr 15 PHP
php+jquery编码方面的一些心得(utf-8 gb2312)
Oct 12 PHP
解析php多线程下载远程多个文件
Jun 25 PHP
php不允许用户提交空表单(php空值判断)
Nov 12 PHP
php自定义函数实现二维数组排序功能
Jul 20 PHP
thinkphp表单上传文件并将文件路径保存到数据库中
Jul 28 PHP
对php 判断http还是https,以及获得当前url的方法详解
Jan 15 PHP
PHP htmlspecialchars()函数用法与实例讲解
Mar 08 PHP
php面向对象重点知识分享
Sep 27 PHP
利用PHP内置SERVER开启web服务(本地开发使用)
Jan 22 PHP
Laravel 框架路由原理与路由访问实例分析
Apr 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 PDO中文乱码解决办法
2009/07/20 PHP
php解压文件代码实现php在线解压
2014/02/13 PHP
ThinkPHP学习笔记(一)ThinkPHP部署
2014/06/22 PHP
php中将一段数据存到一个txt文件中并显示其内容
2014/08/15 PHP
Yii2.0中使用js异步删除示例
2017/03/10 PHP
PHP ADODB实现事务处理功能示例
2018/05/25 PHP
基于Jquery实现的一个图片滚动切换
2012/06/21 Javascript
jQuery setTimeout传递字符串参数报错的解决方法
2014/06/09 Javascript
JavaScript学习笔记之检测客户端类型是(引擎、浏览器、平台、操作系统、移动设备)
2015/12/03 Javascript
JS产生随机数的用法小结
2016/12/10 Javascript
bootstrap suggest下拉框使用详解
2017/04/10 Javascript
jquery加载单文件vue组件的方法
2017/06/20 jQuery
深入理解vue.js中$watch的oldvalue与newValue
2017/08/07 Javascript
express框架实现基于Websocket建立的简易聊天室
2017/08/10 Javascript
了解在JavaScript中将值转换为字符串的5种方法
2019/06/06 Javascript
详解package.json版本号规则
2019/08/01 Javascript
[02:54]辉夜杯主赛事第二日败者组 iG.V赛后采访
2015/12/26 DOTA
Python爬虫之xlml解析库(全面了解)
2017/08/08 Python
使用Django启动命令行及执行脚本的方法
2018/05/29 Python
redis之django-redis的简单缓存使用
2018/06/07 Python
在Pandas中给多层索引降级的方法
2018/11/16 Python
python实现从pdf文件中提取文本,并自动翻译的方法
2018/11/28 Python
Python3获取电脑IP、主机名、Mac地址的方法示例
2019/04/11 Python
TensorFlow——Checkpoint为模型添加检查点的实例
2020/01/21 Python
快速解决Django关闭Debug模式无法加载media图片与static静态文件
2020/04/07 Python
python使用自定义钉钉机器人的示例代码
2020/06/24 Python
中国专业的音频分享平台:喜马拉雅
2019/05/24 全球购物
Rentalcars.com中国:世界上最大的在线汽车租赁服务
2019/08/22 全球购物
JAVA中的关键字有什么特点
2014/03/07 面试题
财务会计专业推荐信
2013/11/30 职场文书
经典的毕业生自荐信范文
2014/04/14 职场文书
对外汉语教师推荐信
2015/03/27 职场文书
无罪辩护词范文
2015/05/21 职场文书
幼儿园元旦主持词
2015/07/06 职场文书
Mysql8.0递归查询的简单用法示例
2021/08/04 MySQL
python单向链表实例详解
2022/05/25 Python