首頁 >後端開發 >PHP問題 >php 實作類似pyhon中的Construct函式庫的功能(一) 基本設計思路

php 實作類似pyhon中的Construct函式庫的功能(一) 基本設計思路

王林
王林轉載
2019-08-19 17:12:422133瀏覽

引言

在python中有一個函式庫Construct ,可以用來解析二進位數據,用這個工具分析網路包,帶格式的資料檔等等很方便。

前一陣分析sqlite資料庫檔案格式時要是用這種工具,也可以省不少事。

不過Construct2.9與以前的版本,改動很大,原來用Construct寫的python程式碼,基本上要重新改寫了。在檢視Construct原始碼的過程中,發現Construct的基本實作想​​法是遞歸下降分析法。用物件的建構方法來動態定義資料結構,在parse方法中實作對二進位資料的解析。

打算用php實作二進位資料的解析,但是在實作思路上與python的Construct完全不一樣。

推薦PHP影片教學:https://www.php.cn/course/list/29/type/2.html

基本想法

由於python的Construct用python的物件語法來實現動態層次結構的定義與解析,受限於python的物件語法,因此有一些結構定義看起來很晦澀。

我的想法是定義一個小小的,專門用來描述動態層次結構的語言,這樣一來就可以盡量的照顧人們常用的表達習慣。

以這個小專案來說,以C語言中的結構體定義語法為藍本,在此基礎上增加條件化,循環環的結構定義。

在二進位資料中有一個常見的結構,前面幾個位元組存放後面資料塊的長度,接下來才是資料塊。這種結構用C語言的結構體定義表示時並不方便。整個資料塊的長度是變化的,在編譯時無法確定,只能在解析時才能確定。因此有必要對C語言的結構體定義語法進行擴展。

第一步,實現對C語言結構體的解析

在這一步,先不考慮動態的層次的結構體定義,而是實現這個小語言的最核心的部分,至少它要能理解C語言的結構體定義,並能根據這個結構體定義對二進位資料進行解析。這一步驟完成後再實現動態的結構體的定義與解析。

本專案是基於前面文件中簡單介紹過的ADOS腳本語言引擎。

先來看看我們的任務

這裡有一個完全是C語言規格的結構體定義檔

blockStruct.h

struct student
{
  char name[2];
  int num;
  int age;
  char addr[3];
};

struct teacher
{
  char name[2];
  int num;  
  char addr[3];
};

待解析的二進位資料塊

"\x41\x42\x01\x00\x00\x00\x02\x00\x00\x00\x41\x42\x43\x41\x42\x01\x00\x00\x00\x41\x42\x43"

希望得到的解析結果

[value] => Array
        (
            [name] => AB
            [num] => 1
            [age] => 2
            [addr] => ABC
        )
[value] => Array
        (
            [name] => AB
            [num] => 1
            [addr] => ABC
        )

有興趣的朋友可以留意一下這三者之間的關係

下而是僅實現了對C語言結構體進行編譯的詞法規則檔

<?php
/*!
 * struckwkr的词法规则
 * 45022300@qq.com
 * Version 0.9.0
 *
 * Copyright 2019, Zhu Hui
 * Released under the MIT license
 */

$GLOBALS[&#39;structwkr_lexRules&#39;] =	[
		[&#39;/^\"(.*?)\"/&#39;,&#39;_cons&#39;	,&#39;"&#39;],
		[&#39;/^\(/&#39;,&#39;_lp&#39;			,&#39;(&#39;],
		[&#39;/^\)/&#39;,&#39;_rp&#39;			,&#39;)&#39;],
		[&#39;/^\[/&#39;,&#39;_lb&#39;			,&#39;[&#39;],
		[&#39;/^\]/&#39;,&#39;_rb&#39;			,&#39;]&#39;],
		[&#39;/^\{/&#39;,&#39;_lcb&#39;			,&#39;{&#39;],
		[&#39;/^\}/&#39;,&#39;_rcb&#39;			,&#39;}&#39;],
		[&#39;/^;/&#39;,&#39;_semi&#39;			,&#39;;&#39;],
		[&#39;/^,/&#39;,&#39;_comma&#39;		,&#39;,&#39;],
		[&#39;/^==/&#39;,&#39;_bieq&#39;		,&#39;=&#39;],
		[&#39;/^!=/&#39;,&#39;_uneq&#39;		,&#39;!&#39;],		
		[&#39;/^\>=/&#39;,&#39;_greq&#39;		,&#39;>&#39;],		
		[&#39;/^\<=/&#39;,&#39;_leeq&#39;		,&#39;<&#39;],		
		[&#39;/^=/&#39;,&#39;_equa&#39;			,&#39;=&#39;],		
		[&#39;/^\>/&#39;,&#39;_grea&#39;		,&#39;>&#39;],
		[&#39;/^\</&#39;,&#39;_less&#39;		,&#39;<&#39;],	
		[&#39;/^\+/&#39;,&#39;_add&#39;			,&#39;+&#39;],
		[&#39;/^-/&#39;,&#39;_sub&#39;			,&#39;-&#39;],
		[&#39;/^\*/&#39;,&#39;_mul&#39;			,&#39;*&#39;],
		[&#39;/^\//&#39;,&#39;_div&#39;			,&#39;/&#39;],	
		[&#39;/^%/&#39;,&#39;_mod&#39;			,&#39;$&#39;],
		[&#39;/^&&/&#39;,&#39;_and&#39;			,&#39;&&#39;],	
		[&#39;/^\|\|/&#39;,&#39;_or&#39;		,&#39;|&#39;],	
		[&#39;/^!/&#39;,&#39;_not&#39;			,&#39;!&#39;],	
		[&#39;/^struct/&#39;,&#39;_strukey&#39;	,&#39;s&#39;],
		[&#39;/^char/&#39;,&#39;_char&#39;		,&#39;c&#39;],
		[&#39;/^int/&#39;,&#39;_int&#39;		,&#39;i&#39;],
		[&#39;/^float/&#39;,&#39;_float&#39;	,&#39;f&#39;],
		[&#39;/^double/&#39;,&#39;_double&#39;	,&#39;d&#39;],
		[&#39;/^[0-9]+([.]{1}[0-9]+){0,1}/&#39;,&#39;_num&#39;,&#39;&#39;],
		[&#39;/^\./&#39;,&#39;_dot&#39;			,&#39;.&#39;],
		[&#39;/^[\x{4e00}-\x{9fa5}A-Za-z_][\x{4e00}-\x{9fa5}A-Za-z0-9_]*\b/u&#39;,&#39;_iden&#39;,&#39;&#39;],
		[&#39;/^\s*/&#39;,&#39;_null&#39;,&#39;&#39;]
		];

下面是僅實現了對C語言結構體進行編譯的語法規則檔

<?php
/*!
 * structwkr的语法规则处理器
 * 45022300@qq.com
 * Version 0.9.0
 *
 * Copyright 2019, Zhu Hui
 * Released under the MIT license
 */

namespace Ados;

require_once &#39;const.php&#39;;
require_once __SCRIPTCORE__.&#39;syntax_rule/base_rules_handler.php&#39;;

class StructwkrRulesHandler extends BaseRulesHandler{

//语法分析的起始记号,归约到最后得到就是若干个结构体定义的列表
function startToken(){
	return &#39;_structList&#39;;
}

//附加类型
function extraType($extraArray){
	if(count($extraArray)>0){
		return $extraArray[0];
	}else{
		return &#39;&#39;;
	}
}

//求出放在附加信息中的数组长度
function elementSize($extraArray){
	if(count($extraArray)>0){
		return intval($extraArray[0]);
	}else{
		return 0;
	}
}

//处理源代码中的多条声明语句
function handleStatementList($stack,$coder,$listIndex,$statementIndex){
	
	$t1= $this->topItem($stack,$statementIndex);	

	if($listIndex>0){
		$t2= $this->topItem($stack,$listIndex);
		//将元素名所在项的附加信息数组找出来
		$extraArray=$t2[TokenExtraIndex];
	}else{ //$listIndex=0表示,statementList是上级节点,附加信息数组应该是空数组
		$extraArray=[];
	}
	//将statement中的附加信息添加到statementList的附加信息中去
	$extraArray[]=$t1[TokenExtraIndex];

	return [&#39;#&#39;,$extraArray];
}

//处理源代码中的一条声明语句
function handleStatement($stack,$coder,$typeItemIndex,$idenItemIndex){
	
	$t1= $this->topItem($stack,$typeItemIndex);
	$elementType = 	$t1[TokenValueIndex];

	$t2= $this->topItem($stack,$idenItemIndex);
	$elementName = 	$t2[TokenValueIndex];
	
	//将元素名所在项的附加信息数组找出来
	$extraArray=$t2[TokenExtraIndex];
	$valLen =$extraArray[0];
	//附加信息中包含 元素名称,元素类型,数据长度
	return [$elementName,[$elementName,$elementType,$valLen]];
}


//语法规则处理函数名由规则右边部分与规则左边部分拼接而成
//语法规则定义的先后决定了归约时匹配的顺序,要根据实际的语法安排
//如果不熟悉语法,随意调整语法规则的先后次序将有可能导致语法错误

// struct list  {{{

function _structList_0_structList_struct($stack,$coder){

	$coder->pushBlockTail();
	return [&#39;#&#39;,[]];
	
	
}

function _structList_0_struct($stack,$coder){	
	$coder->pushBlockTail();
	return [&#39;#&#39;,[]];
}

// 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->handleStatementList($stack,$coder,2,1);
}

function _statementList_0_statement($stack,$coder){
	//此处0表示statementList是上一级节点,要做特殊处理
	return $this->handleStatementList($stack,$coder,0,1);	
}

// statement list  }}}


// statement       {{{

function _statement_0_double_term_semi($stack,$coder){	

	$t1= $this->topItem($stack,2);
	$elementName = 	$t1[TokenValueIndex];
	$parseFuncName = &#39;parseDouble&#39;;	
	$coder->pushBlockBody($parseFuncName,$elementName);	
	
	return $this->handleStatement($stack,$coder,3,2);
}

function _statement_0_float_term_semi($stack,$coder){	

	$t1= $this->topItem($stack,2);
	$elementName = 	$t1[TokenValueIndex];
	$parseFuncName = &#39;parseFloat&#39;;	
	$coder->pushBlockBody($parseFuncName,$elementName);	
	
	return $this->handleStatement($stack,$coder,3,2);
}


function _statement_0_char_term_semi($stack,$coder){

	$t1= $this->topItem($stack,2);
	$elementName = 	$t1[TokenValueIndex];
	$size = $this->elementSize($t1[TokenExtraIndex]);
	$parseFuncName = &#39;parseFixStr&#39;;	
	$coder->pushBlockBody($parseFuncName,$elementName,$size);		
	
	return $this->handleStatement($stack,$coder,3,2);
}

function _statement_0_int_term_semi($stack,$coder){	

	$t1= $this->topItem($stack,2);
	$elementName = 	$t1[TokenValueIndex];
	$parseFuncName = &#39;parseInt&#39;;	
	$coder->pushBlockBody($parseFuncName,$elementName,4);	
	
	return $this->handleStatement($stack,$coder,3,2);
}

// statement        }}}


//   term    {{{

function _term_0_term_array($stack,$coder){

	$t1= $this->topItem($stack,1);
	$valLen = 	$t1[TokenValueIndex];
	//将数据长度放入附加信息 
	$t2= $this->topItem($stack,2);
	return [$t2[TokenValueIndex],[$valLen]];
	
	
}

function _term_0_iden($stack,$coder){
	$t1= $this->topItem($stack,1);
	//未指定数据长度时将长度值设为0 
	$valLen = 	&#39;0&#39;;	
	$t2= $this->topItem($stack,2);
	return [$t1[TokenValueIndex],[$valLen]];	
}

//   term     }}}


// array 	  {{{

function _array_0_lb_num_rb($stack,$coder){

	return $this->pass($stack,2);	
}

// array 	   }}}


} // end of class

下面是對基本數據類型,整數,字串的解析函數(備註,用於實驗,還沒有覆蓋全部的基本資料類型)

<?php

//用于解析基本数据类型的内置函数

namespace Ados;

//解析一个字节,得到无符号整数值
function parseByte($context,$size = 0){
	$pos=$context[&#39;pos&#39;];
	$data = substr($context[&#39;data&#39;], $pos);
	if(strlen($data)>0){
		$raw = substr($data, 0,1);
		$value = unpack("C1",$raw)[1];
		return [&#39;value&#39;=>$value,&#39;size&#39;=>1,&#39;error&#39;=>0,&#39;msg&#39;=>&#39;ok&#39;];
	}else{
		return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>1,&#39;msg&#39;=>&#39;not enough for parseByte&#39;];
	}
	
}

//解析一个有符号整数
function parseInt($context,$size = 4){
	if(!($size == 2 or $size == 4 or $size == 8 )){
		return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>2,&#39;msg&#39;=>&#39;not a valid size&#39;];
	}
	if($size == 2) $format = "s1";
	if($size == 4) $format = "l1";
	if($size == 8) $format = "q1";

	$pos=$context[&#39;pos&#39;];
	$data = substr($context[&#39;data&#39;], $pos);
	if(strlen($data)>=$size){
		$raw = substr($data, 0,$size);
		$value = unpack($format,$raw)[1];
		return [&#39;value&#39;=>$value,&#39;size&#39;=>$size,&#39;error&#39;=>0,&#39;msg&#39;=>&#39;ok&#39;];
	}else{
		return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>1,&#39;msg&#39;=>&#39;no data for parseInt&#39;];
	}
	
}

//解析一个大端无符号整数
function parseBUInt($context,$size = 4){
	if(!($size == 2 or $size == 4 or $size == 8 )){
		return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>2,&#39;msg&#39;=>&#39;not a valid size&#39;];
	}
	if($size == 2) $format = "n1";
	if($size == 4) $format = "N1";
	if($size == 8) $format = "J1";

	$pos=$context[&#39;pos&#39;];
	$data = substr($context[&#39;data&#39;], $pos);
	if(strlen($data)>=$size){
		$raw = substr($data, 0,$size);
		$value = unpack($format,$raw)[1];
		return [&#39;value&#39;=>$value,&#39;size&#39;=>$size,&#39;error&#39;=>0,&#39;msg&#39;=>&#39;ok&#39;];
	}else{
		return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>1,&#39;msg&#39;=>&#39;no data for parseBUInt&#39;];
	}
	
}

//解析一个小端无符号整数
function parseLUInt($context,$size = 4){
	if(!($size == 2 or $size == 4 or $size == 8 )){
		return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>2,&#39;msg&#39;=>&#39;not a valid size&#39;];
	}
	if($size == 2) $format = "v1";
	if($size == 4) $format = "NL";
	if($size == 8) $format = "P1";

	$pos=$context[&#39;pos&#39;];
	$data = substr($context[&#39;data&#39;], $pos);
	if(strlen($data)>=$size){
		$raw = substr($data, 0,$size);
		$value = unpack($format,$raw)[1];
		return [&#39;value&#39;=>$value,&#39;size&#39;=>$size,&#39;error&#39;=>0,&#39;msg&#39;=>&#39;ok&#39;];
	}else{
		return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>1,&#39;msg&#39;=>&#39;no data for parseLUInt&#39;];
	}
	
}

//解析一个null结束的字符串
function parseString($context,$size=0){
	$pos=$context[&#39;pos&#39;];
	$data = substr($context[&#39;data&#39;], $pos);

	$p=0;
	$raw = substr($data, $p,1);
	$byte = unpack("C1",$raw)[1];	
	$result =&#39;&#39;;
	while($byte){
		$result.=$raw;
		$p++;
		if($p>=strlen($data)){
			return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>1,&#39;msg&#39;=>&#39;not find null end for parseString&#39;];
		}
		$raw = substr($data, $p,1);
		$byte = unpack("C1",$raw)[1];		
	}
	return [&#39;value&#39;=>$result,&#39;size&#39;=>$p,&#39;error&#39;=>0,&#39;msg&#39;=>&#39;ok&#39;];
}

//解析一个定长字符串
function parseFixStr($context,$size=0){
	$pos=$context[&#39;pos&#39;];
	$data = substr($context[&#39;data&#39;], $pos);
	//var_dump($data);	
	if(strlen($data)>=$size){
		$result =&#39;&#39;;
		for($i=0;$i<$size;$i++){
			$raw = substr($data, $i,1);
			$value = unpack("a1",$raw)[1];
			$result.=$value;			
		}
		return [&#39;value&#39;=>$result,&#39;size&#39;=>$size,&#39;error&#39;=>0,&#39;msg&#39;=>&#39;ok&#39;]; 
	}
	return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>1,&#39;msg&#39;=>&#39;not enough for parseFixedString&#39;];
}

下面是用於模板替換的工作函數

<?php

//用于进行模板替换的工作函数

namespace Ados;

defined(&#39;__STRUCT_PARSE_TEMP__&#39;) or define(&#39;__STRUCT_PARSE_TEMP__&#39;, &#39;./&#39;);
define(&#39;_blockParsTempFile_&#39;,__STRUCT_PARSE_TEMP__.&#39;parseFunc.template.php&#39;);

//取出两个记号串之间的内容
function strBetweenToke($src,$toke1,$toke2){
	$p1 = strpos($src,$toke1);
	$p2 = strpos($src,$toke2);
	return substr($src,$p1+strlen($toke1),$p2-$p1-strlen($toke1));
}

//取得块分析函数的header
function blockHeaderStr(){
	$src = file_get_contents(_blockParsTempFile_);
	return strBetweenToke($src,&#39;/*blockHeader{{*/&#39;,&#39;/*blockHeader}}*/&#39;);
}

//取得块分析函数的body
function blockBodyStr(){
	$src = file_get_contents(_blockParsTempFile_);
	return strBetweenToke($src,&#39;/*blockBody{{*/&#39;,&#39;/*blockBody}}*/&#39;);
}

//取得块分析函数的tail
function blockTailStr(){
	$src = file_get_contents(_blockParsTempFile_);
	return strBetweenToke($src,&#39;/*blockTail{{*/&#39;,&#39;/*blockTail}}*/&#39;);
}

define(&#39;_blockHeaderStr_&#39;,blockHeaderStr());
define(&#39;_blockBodyStr_&#39;,blockBodyStr());
define(&#39;_blockTailStr_&#39;,blockTailStr());

function makeBlockHeader($blockName){
	return str_replace(&#39;parseBlock_Temp&#39;, &#39;parse&#39;.$blockName, _blockHeaderStr_);
}

function makeblockBody($parseFuncName,$filedName=&#39;&#39;,$filedSize=0){
	$tmp = str_replace(&#39;parseByte&#39;, $parseFuncName, _blockBodyStr_);
	$tmp = str_replace(&#39;$filedName&#39;, $filedName, $tmp);
	$tmp = str_replace(&#39;$filedSize&#39;, $filedSize, $tmp);
	return $tmp;
}

function makeblockTail(){
	return _blockTailStr_ ;
}


/*
echo blockHeaderStr();
echo blockBodyStr();
echo blockTailStr();

echo makeBlockHeader(&#39;Test1&#39;);
echo makeblockBody(&#39;parseInt&#39;);
echo makeblockBody(&#39;parseStr&#39;);
echo makeblockTail();
*/

有了這些準備工作後,就可以實作一個語法導引的編碼器,用於產生最終的解析函數。
下而就是一個簡單的編碼器,在對結構體定義進行語法分析時,產生可用於解析二進位資料的腳本代碼

<?php
/*!
 * structwkr编码器,
 *
 * 45022300@qq.com
 * Version 0.9.0
 *
 * Copyright 2019, Zhu Hui
 * Released under the MIT license
 */

namespace Ados;

require_once __SCRIPTCORE__.&#39;coder/base_coder.php&#39;;
require_once __STRUCT_PARSE_TEMP__.&#39;templateReplaceFuncs.php&#39;;


class StructwkrCoder extends BaseCoder{

	public function __construct($engine)
	{
		if($engine){ 
			$this->engine = $engine;
		}else{ 
			exit(&#39;the engine is not valid in StructwkrCoder construct.&#39;);
		}
	}

	//编译得到的最终结果
	public function codeLines(){
		if(count($this->codeLines)<1){
			return &#39;&#39;;
		}
		$script=&#39;&#39;;		
		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 pushBlockBody($parseFuncName,$filedName=&#39;&#39;,$filedSize=0){
		$content = makeblockBody($parseFuncName,$filedName,$filedSize);
		array_push($this->codeLines, $content);
		$lineIndex=$this->lineIndex;
		$this->lineIndex+=1;
		return $lineIndex;		
	}

	//添加一个块解析函数尾
	public function pushBlockTail(){
		$content = makeblockTail();
		array_push($this->codeLines, $content);
		$lineIndex=$this->lineIndex;
		$this->lineIndex+=1;
		return $lineIndex;		
	}

}

自動產生的用於解析的腳本文件

對c語言的結構體進行編譯,最終得到可以用來解析二進位資料的一系列函數,例如上述結構體定義檔中定義了兩個結構體

struct student
{
  char name[2];
  int num;
  int age;
  char addr[3];
};

struct teacher
{
  char name[2];
  int num;  
  char addr[3];
};

那麼就會產生與這兩個結構體對應的解析函數parseStudentparseTeacher

下面就是自動產生的測試腳本

False,'size'=>0,'error'=>$expRes['error'],'msg'=>$expRes['msg']];
	}

	$expRes = parseInt($context,4);
	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'];
}

function parseTeacher($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);
	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] => AB
            [num] => 1
            [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
)

OK ! 第一步的任務已經完成,接下來考慮實現一個帶有條件判斷的結構體的解析工作。

更多相關問題請上PHP中文網:https://www.php.cn/

#

以上是php 實作類似pyhon中的Construct函式庫的功能(一) 基本設計思路的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除