各类知识收集,PHP技术分享与解决方案各类知识收集,PHP技术分享与解决方案各类知识收集,PHP技术分享与解决方案

Str Tom,为分享PHP技术和解决方案,贡献一份自己的力量!
收藏本站(不迷路),每天更新好文章!
当前位置:首页 > CMS教程 > PHP

PHP实现类似于Python中的Construct库功能(二)实现适配器功能

管理员 2023-09-05
PHP
121

PHP实现类似于Python中的Construct库功能(二)实现适配器功能

内容导读

收集整理的这篇技术教程文章主要介绍了PHP实现类似于Python中的Construct库功能(二)实现适配器功能,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含13228字,纯文字阅读大概需要19分钟

内容图文

引言

在上一篇文章《PHP实现类似于Python中的Construct库功能(二)实现适配器功能》介绍了用php解析二进制数据的基本思路。接下来要完成两个工作。

1、在上一篇文章中采用解析函数的方式,现在改成用解析类,在类中包含parse方法。

2、在定义结构体数据项时,加上适配器功能,用管道运算符| 连接数据项与适配器,实现数据的变换。

推荐PHP视频教程:https://www.gxlcms.com/course/list/29/type/2.html

基本思路

1,修改词法分析规则,使其可以接受管道运算符 |

2,修改语法分析规则,使其可以接受适配器的调用

3,用php语言实现适配器功能

实现内容

准备解析的结构体定义文件

struct student{  char name[2];  int num|IntOffset(100);  int age;  char addr[3];};struct teacher{  char name[2];  int num|Int2str;   char addr[3];};

与上一篇文章中的结构体定义最大的不同在于以下这两句

  int num|IntOffset(100);   int num|Int2str;  };

这里通过管道调用了两个适配器,IntOffset(100) 表示在原有值的基础上偏移100,Int2str表示将原有的整数值变成字符串

下面看一下这两个适配器的具体实现

<?php//将整数值偏移一个定值namespace Ados;class IntOffset {	public function __construct($offset)	{				$this->offset = $offset;			}	function parse($obj){		if(is_array($obj)){			return array_map(function($value) {					    return $value + $this->offset;					},$obj);		}		return $obj+ $this->offset;	}	function build($obj){		throw new Exception("Int2str build method not implements");	}}class Int2str {	function parse($obj){		if(is_array($obj)){			return array_map(function($value) {					    return ''.$value;					},$obj);		}		return ''.$obj;	}	function build($obj){		throw new Exception("Int2str build method not implements");	}}

为了集中注意力在二进制数据的解析上,以上两个类中只实现了parse方法,build方法暂未实现。

相应的,模板文件也要有所调整

<?php//用于进行替换的模板文本/*blockHeader{{*/class structName{	static function parse($context,$size=0){		$valueArray=[];		$totalSize = 0;	/*blockHeader}}*/	/*parseBody{{*/		$expRes = parseByte($context,$filedSize);	/*parseBody}}*/	/*pipeBody{{*/		$expRes['value'] = (new Adapter())->parse($expRes['value']);			/*pipeBody}}*/	/*checkBody{{*/		if($expRes['error']==0){			$filed = '$filedName';			if($filed){				$valueArray[$filed]=$expRes['value'];			}else{				$valueArray[]=$expRes['value'];			}					$context['pos']+=$expRes['size'];			$totalSize+= $expRes['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$expRes['error'],'msg'=>$expRes['msg']];		}	/*checkBody}}*/		/*blockTail{{*/		return ['value'=>$valueArray,'size'=>$totalSize,'error'=>0,'msg'=>'ok'];	}}	/*blockTail}}*/

词法规则文件改动不大,增加对管道运算符的匹配就可以了

['/^|/','_pipe'		,'|'],

语法规则文件改动得比较大,由于要能够分析这一类语句

 int num|IntOffset(100);

修改后的语法规则文件内容如下:

<?php/*! * structwkr的语法规则处理器 * 45022300@qq.com * Version 0.9.0 * * Copyright 2019, Zhu Hui * Released under the MIT license */namespace Ados;require_once 'const.php';require_once __SCRIPTCORE__.'syntax_rule/base_rules_handler.php';class StructwkrRulesHandler extends BaseRulesHandler{//语法分析的起始记号,归约到最后得到就是若干个结构体定义的列表function startToken(){	return '_structList';}//求出放在附加信息中的数组长度function elementSize($extraArray){	if(count($extraArray)>0){		return intval($extraArray[0]);	}else{		return 0;	}}//语法规则处理函数名由规则右边部分与规则左边部分拼接而成//语法规则定义的先后决定了归约时匹配的顺序,要根据实际的语法安排//如果不熟悉语法,随意调整语法规则的先后次序将有可能导致语法错误// struct list  {{{function _structList_0_structList_struct($stack,$coder){	$coder->pushBlockTail();	return ['#',[]];		}function _structList_0_struct($stack,$coder){		$coder->pushBlockTail();	return ['#',[]];}// struct list  }}}// struct   {{{function _struct_0_structName_blockStatement_semi($stack,$coder){	$t1= $this->topItem($stack,3);	$structName = 	$t1[TokenValueIndex];	$t2= $this->topItem($stack,2);	$extraArray=$t2[TokenExtraIndex];		return [$structName,$extraArray];}// struct   }}}// struct name     {{{function _structName_0_strukey_iden($stack,$coder){  	$t1= $this->topItem($stack,1);	$structName = 	$t1[TokenValueIndex];	$coder->pushBlockHeader($structName);		return $this->pass($stack,1);}// struct name     }}}// blockStatement    {{{function _blockStatement_0_lcb_statementList_rcb($stack,$coder){	return $this->pass($stack,2);}// blockStatement    }}}// statement list  {{{function _statementList_0_statementList_statement($stack,$coder){		return $this->pass($stack,1);}function _statementList_0_statement($stack,$coder){	//此处0表示statementList是上一级节点,要做特殊处理	return $this->pass($stack,1);}// statement list  }}}// statement       {{{function _statement_0_expression_semi($stack,$coder){	$t1= $this->topItem($stack,2);	$elementName = 	$t1[TokenValueIndex];		$coder->pushCheckBody($elementName);		return $this->pass($stack,2);}// statement        }}}// function expression {{{//函数表达式function _term_0_funcTerm($stack,$coder){  	$t1= $this->topItem($stack,1);	$funcName=$t1[TokenValueIndex];	$paraArray=$t1[TokenExtraIndex]; 	$paras = implode(",", $paraArray);	$exp = $funcName.'('.$paras.')';		return [$exp,[]];}function _funcTerm_0_funcExpLp_rp($stack,$coder){  	return $this->pass($stack,2);}function _funcTerm_0_funcExpLeft_rp($stack,$coder){  	return $this->pass($stack,2);}function _funcExpLeft_0_funcExpLeft_comma_expression($stack,$coder){  				$t1= $this->topItem($stack,3);	$t2= $this->topItem($stack,1);	//函数的参数列表存放在附加信息中	$paraArray=$t1[TokenExtraIndex]; 	array_push($paraArray, $t2[TokenValueIndex]);		return [$t1[TokenValueIndex],$paraArray];}function _funcExpLeft_0_funcExpLp_expression($stack,$coder){  		$t1= $this->topItem($stack,2);	$t2= $this->topItem($stack,1);	//函数的参数列表存放在附加信息中	$paraArray=$t1[TokenExtraIndex]; 	array_push($paraArray, $t2[TokenValueIndex]);		return [$t1[TokenValueIndex],$paraArray];}function _funcExpLp_0_iden_lp($stack,$coder){  		return $this->pass($stack,2);}// function expression }}}//    Expression         {{{//表达式可以进行管道运算function _expression_0_expression_pipe_factor($stack,$coder){	$t1= $this->topItem($stack,1);	$handlerName = 	$t1[TokenValueIndex];	$coder->pushPipeBody($handlerName);			return $this->pass($stack,3);}function _expression_0_double_factor($stack,$coder){		$t1= $this->topItem($stack,1);	$elementName = 	$t1[TokenValueIndex];	$parseFuncName = 'parseDouble';		$coder->pushParseBody($parseFuncName,$elementName);			return $this->pass($stack,1);}function _expression_0_float_factor($stack,$coder){		$t1= $this->topItem($stack,1);	$elementName = 	$t1[TokenValueIndex];	$parseFuncName = 'parseFloat';		$coder->pushParseBody($parseFuncName,$elementName);			return $this->pass($stack,1);}function _expression_0_char_factor($stack,$coder){	$t1= $this->topItem($stack,1);	$elementName = 	$t1[TokenValueIndex];	$size = $this->elementSize($t1[TokenExtraIndex]);		$parseFuncName = 'parseFixStr';		$coder->pushParseBody($parseFuncName,$elementName,$size);				return $this->pass($stack,1);}function _expression_0_int_factor($stack,$coder){		$t1= $this->topItem($stack,1);	$elementName = 	$t1[TokenValueIndex];	$parseFuncName = 'parseInt';		$coder->pushParseBody($parseFuncName,$elementName,4);			return $this->pass($stack,1);}function _expression_0_factor($stack,$coder){		return $this->pass($stack,1);}//   Expression         }}}// factor       {{{function _factor_0_term($stack,$coder){		return $this->pass($stack,1);}//  factor        }}}//   term    {{{function _term_0_iden($stack,$coder){	$t1= $this->topItem($stack,1);	//未指定数据长度时将长度值设为0 	$valLen = 	'0';		$t2= $this->topItem($stack,2);	return [$t1[TokenValueIndex],[$valLen]];	}function _term_0_num($stack,$coder){	return $this->pass($stack,1);}function _term_0_array($stack,$coder){	return $this->pass($stack,1);}//   term     }}}// array 	  {{{function _array_0_arrayLb_num_rb($stack,$coder){	$t1= $this->topItem($stack,2);	$valLen = 	$t1[TokenValueIndex];			$t2= $this->topItem($stack,3);	//将数据长度放入附加信息 	return [$t2[TokenValueIndex],[$valLen]];		}function _arrayLb_0_iden_lb($stack,$coder){  	return $this->pass($stack,2);}// array 	   }}}}// end of class

编码器也要做相应的调整,增加对管道运算的处理

<?php/*! * structwkr编码器, * * 45022300@qq.com * Version 0.9.0 * * Copyright 2019, Zhu Hui * Released under the MIT license */namespace Ados;require_once __SCRIPTCORE__.'coder/base_coder.php';require_once __STRUCT_PARSE_TEMP__.'templateReplaceFuncs.php';class StructwkrCoder extends BaseCoder{	public function __construct($engine)	{		if($engine){ 			$this->engine = $engine;		}else{ 			exit('the engine is not valid in StructwkrCoder construct.');		}	}	//编译得到的最终结果	public function codeLines(){		if(count($this->codeLines)<1){			return '';		}		$script='';				for ($i=0;$i< count($this->codeLines);$i+=1) {			$script.=$this->codeLines[$i];		}			return $script;	}		//
输出编译后的结果 public function printCodeLines(){ echo $this->codeLines(); } //添加一个块解析函数头 public function pushBlockHeader($structName){ $structName=ucfirst($structName); $content = makeBlockHeader($structName); array_push($this->codeLines, $content); $lineIndex=$this->lineIndex; $this->lineIndex+=1; return $lineIndex; } //添加一个块解析函数体 public function pushParseBody($parseFuncName,$filedName='',$filedSize=0){ $content = makeParseBody($parseFuncName,$filedName,$filedSize); array_push($this->codeLines, $content); $lineIndex=$this->lineIndex; $this->lineIndex+=1; return $lineIndex; } //添加一个管道处理 public function pushPipeBody($handler){ $content = makePipeBody($handler); array_push($this->codeLines, $content); $lineIndex=$this->lineIndex; $this->lineIndex+=1; return $lineIndex; } //添加一个检查结果值的body public function pushCheckBody($filedName=''){ $content = makeCheckBody($filedName); array_push($this->codeLines, $content); $lineIndex=$this->lineIndex; $this->lineIndex+=1; return $lineIndex; } //添加一个块解析类的tail public function pushBlockTail(){ $content = makeblockTail(); array_push($this->codeLines, $content); $lineIndex=$this->lineIndex; $this->lineIndex+=1; return $lineIndex; }}

实现结果

自动生成的测试文件如下

<?phpnamespace Ados;//加载常量定义文件require_once 'const.php';require_once __STRUCT_PARSE_TEMP__.'templateBuidinFuncs.php';require_once __STRUCT_PARSE_ADAPTER__.'int2str.adapter.php';require_once __STRUCT_PARSE_ADAPTER__.'intoffset.adapter.php';$context['pos']=0;$context['data']="x41x43x01x00x00x00x02x00x00x00x41x42x43x41x42x01x00x00x00x41x42x43";$expRes = Student::parse($context);$context['pos']+=$expRes['size'];print_r($expRes);$expRes = Teacher::parse($context);$context['pos']+=$expRes['size'];print_r($expRes);class Student{	static function parse($context,$size=0){		$valueArray=[];		$totalSize = 0;			$expRes = parseFixStr($context,2);			if($expRes['error']==0){			$filed = 'name';			if($filed){				$valueArray[$filed]=$expRes['value'];			}else{				$valueArray[]=$expRes['value'];			}					$context['pos']+=$expRes['size'];			$totalSize+= $expRes['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$expRes['error'],'msg'=>$expRes['msg']];		}			$expRes = parseInt($context,4);			$expRes['value'] = (new IntOffset(100))->parse($expRes['value']);					if($expRes['error']==0){			$filed = 'num';			if($filed){				$valueArray[$filed]=$expRes['value'];			}else{				$valueArray[]=$expRes['value'];			}					$context['pos']+=$expRes['size'];			$totalSize+= $expRes['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$expRes['error'],'msg'=>$expRes['msg']];		}			$expRes = parseInt($context,4);			if($expRes['error']==0){			$filed = 'age';			if($filed){				$valueArray[$filed]=$expRes['value'];			}else{				$valueArray[]=$expRes['value'];			}					$context['pos']+=$expRes['size'];			$totalSize+= $expRes['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$expRes['error'],'msg'=>$expRes['msg']];		}			$expRes = parseFixStr($context,3);			if($expRes['error']==0){			$filed = 'addr';			if($filed){				$valueArray[$filed]=$expRes['value'];			}else{				$valueArray[]=$expRes['value'];			}					$context['pos']+=$expRes['size'];			$totalSize+= $expRes['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$expRes['error'],'msg'=>$expRes['msg']];		}			return ['value'=>$valueArray,'size'=>$totalSize,'error'=>0,'msg'=>'ok'];	}}	class Teacher{	static function parse($context,$size=0){		$valueArray=[];		$totalSize = 0;			$expRes = parseFixStr($context,2);			if($expRes['error']==0){			$filed = 'name';			if($filed){				$valueArray[$filed]=$expRes['value'];			}else{				$valueArray[]=$expRes['value'];			}					$context['pos']+=$expRes['size'];			$totalSize+= $expRes['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$expRes['error'],'msg'=>$expRes['msg']];		}			$expRes = parseInt($context,4);			$expRes['value'] = (new Int2str)->parse($expRes['value']);					if($expRes['error']==0){			$filed = 'num';			if($filed){				$valueArray[$filed]=$expRes['value'];			}else{				$valueArray[]=$expRes['value'];			}					$context['pos']+=$expRes['size'];			$totalSize+= $expRes['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$expRes['error'],'msg'=>$expRes['msg']];		}			$expRes = parseFixStr($context,3);			if($expRes['error']==0){			$filed = 'addr';			if($filed){				$valueArray[$filed]=$expRes['value'];			}else{				$valueArray[]=$expRes['value'];			}					$context['pos']+=$expRes['size'];			$totalSize+= $expRes['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$expRes['error'],'msg'=>$expRes['msg']];		}			return ['value'=>$valueArray,'size'=>$totalSize,'error'=>0,'msg'=>'ok'];	}}

运行测试文件的结果

Array(    [value] => Array        (            [name] => AC            [num] => 101            [age] => 2            [addr] => ABC        )    [size] => 13    [error] => 0    [msg] => ok)Array(    [value] => Array        (            [name] => AB            [num] => 1            [addr] => ABC        )    [size] => 9    [error] => 0    [msg] => ok)

对比测试数据

$context['data']="x41x43x01x00x00x00x02x00x00x00x41x42x43x41x42x01x00x00x00x41x42x43";

如果不加适配器
第一个结构体的num字段的结果应是:
[num] => 1

现在加上了适配器
int num|IntOffset(100);

所以结果变成了:
[num] => 101

适配器功能已经实现并得到了验证。

更多相关问题请访问PHP中文网相关视频教程:https://www.gxlcms.com/

以上就是PHP实现类似于Python中的Construct库功能(二)实现适配器功能的详细内容,更多请关注Gxl网其它相关文章!

内容总结

以上是为您收集整理的PHP实现类似于Python中的Construct库功能(二)实现适配器功能全部内容,希望文章能够帮你解决PHP实现类似于Python中的Construct库功能(二)实现适配器功能所遇到的程序开发问题。 如果觉得技术教程内容还不错,欢迎将网站推荐给程序员好友。

内容备注

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

扫码关注

qrcode

QQ交谈

回顶部