0

0

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

王林

王林

发布时间:2019-08-19 16:18:42

|

2953人浏览过

|

来源于CSDN

转载

引言

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

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

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

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

立即学习PHP免费学习笔记(深入)”;

基本思路

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表示将原有的整数值变成字符串

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

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方法暂未实现。

黄城网络办公系统
黄城网络办公系统

具有功能全面实用、安全性稳定性高、易操作、管理维护简单的特点,采用独创的智能型技术,web服务器、数据库和应用程序全部自动傻瓜安装配置,用户可在一分钟内自行安装完毕,无需专业人员即可自行维护,B/S结构,适用于Intranet/Internet应用,客户端只需浏览器便可连接办公系统,无论出差旅行,还是居家办公,工作都能得心应手,实现无地域限制的全球办公,具有邮件管理、业务管理、网络硬盘、智能工作流

下载

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

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);

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

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

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

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;		
	}

}

实现结果

自动生成的测试文件如下

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']="\x41\x43\x01\x00\x00\x00\x02\x00\x00\x00\x41\x42\x43\x41\x42\x01\x00\x00\x00\x41\x42\x43";

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

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

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

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

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

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
微信聊天记录删除恢复导出教程汇总
微信聊天记录删除恢复导出教程汇总

本专题整合了微信聊天记录相关教程大全,阅读专题下面的文章了解更多详细内容。

36

2026.01.18

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

99

2026.01.16

全民K歌得高分教程大全
全民K歌得高分教程大全

本专题整合了全民K歌得高分技巧汇总,阅读专题下面的文章了解更多详细内容。

148

2026.01.16

C++ 单元测试与代码质量保障
C++ 单元测试与代码质量保障

本专题系统讲解 C++ 在单元测试与代码质量保障方面的实战方法,包括测试驱动开发理念、Google Test/Google Mock 的使用、测试用例设计、边界条件验证、持续集成中的自动化测试流程,以及常见代码质量问题的发现与修复。通过工程化示例,帮助开发者建立 可测试、可维护、高质量的 C++ 项目体系。

56

2026.01.16

java数据库连接教程大全
java数据库连接教程大全

本专题整合了java数据库连接相关教程,阅读专题下面的文章了解更多详细内容。

40

2026.01.15

Java音频处理教程汇总
Java音频处理教程汇总

本专题整合了java音频处理教程大全,阅读专题下面的文章了解更多详细内容。

19

2026.01.15

windows查看wifi密码教程大全
windows查看wifi密码教程大全

本专题整合了windows查看wifi密码教程大全,阅读专题下面的文章了解更多详细内容。

107

2026.01.15

浏览器缓存清理方法汇总
浏览器缓存清理方法汇总

本专题整合了浏览器缓存清理教程汇总,阅读专题下面的文章了解更多详细内容。

44

2026.01.15

ps图片相关教程汇总
ps图片相关教程汇总

本专题整合了ps图片设置相关教程合集,阅读专题下面的文章了解更多详细内容。

12

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号