多语言展示
当前在线:1657今日阅读:176今日分享:34

解析器与反射API的集成

首先,将之前清单中的文档块解析器与反射API集成在一起。通过扩展核心的Reflecticn类并且将解析器作为静态方法添加进去,就可以做到这一点。
方法/步骤
1

首先,将之前清单中的文档块解析器与反射API集成在一起。通过扩展核心的Reflecticn类并且将解析器作为静态方法添加进去,就可以做到这一点。    代码显示了这一扩展。将这段代码和所有随后的反射类都放到一个名为DocumentingReflection.php的公共的包含文件中。集成文档注释解析器(DocumentingReflection.php)     Class DocumentingReflection extends Reflection{   Public static function ParseDocComment($docComment){  $returnData =$comments = $tags =$array();  $tagNames = $tagData = array(); $tokens =docblock_tokenize($docComment,true);  Foreach($tokens as $token){   Switch($token[0]){Case DOCBLOCK_TEXT:  If(!isset($tagId)){   $comments[] = $token[1];}else{  If(array_key_exists($tagId,$tagData)){  $tagData[$tagId] .=’’.trim($token[1]);}else{  $tagData[$tagId] = trim($token[1]);}}Break;Case DOCBLOCK_TAG: $tagId = uniquid(); $tagNames[$tagId] = trim($token[1],’@’);Break;}}Foreach($tagData as $tagId =>$data){  $tagName = $tagNames[$tagId];  If(array_key_exists($tagName,$tags)){  If(!is_array($tags[$tagName])){         $backupData = $tags[$tagName];$tags[$tagName] = array();$tags[$tagName] = $backupData;} $tag[$tagName] = $data;}else{  $tags[$tagName] = $data;}}$returnData[‘comments’] = $comments;$returnData[‘tags’] = $tags;$returnData[‘tokens’]=$tokens;Return $returnData;}}

2

现在已经定义了静态函数ParseDocComment.这正是添加附加的处理逻辑功能的地方,例如处理行内标签的功能。但是在实现这些功能之前,需要扩展另外一些反射类。扩展反射类下一个要扩展的类是ReflectionMethod类。这是因为它是最全面的反射实现类,它仍然包含了getDocComment()方法。还需要扩展ReflectionParameter类,但是需要从相关联的方法中获取数据,然后这个方法类的扩展才能实现。下面代码,创建了DocumentingReflectionMethod类,将reflectionMethod类与ParseDocComment类集成。创建DocumentingReflectionMethod类(DocumentingReflection.php)Class DocmentingReflectionMethod extends ReflectionMethod{         Protected $_comments,$_tags,$_tokens,$_declaringClass;  Public function __construct($object,$method){  Parent::__construct($object,$method);   $docComment = $this->getDocComment(); $this->_declaringClass = $object; $parsedComment = DocumentingReflection::ParseDocComment($docComment); $this->_comments = $parsedComment[‘comments’];$this->_tags=$parsedComment[‘tags’];$this->_tokens=$parsedComment[‘tokens’];} Public function printDocTokens(){  Foreach($this->_tokens as $token){  Echo $token[0].”=”;  Echo docblock_token_name($token[1]).’=’;  Print_r($token[1]);  Echo “\n”;}} Public function getParseTags(){ Return $this->_tags;}Public function getParsedComments(){ Return $this->_comments;} }DocumentingReflectionMethod类从ReflectionMethod类继承,从而继承了ReflectionMethod类的所有功能。然后通过调用parent::__construct函数,对基数进行初始化。这个父类的构造过程必须在重写的构造器的第一行上完成,否则,可能出现错误,而且,甚至可能出现没有任何错误解释就崩溃的代码。

3

在基类实例初始化完成之后,文档扩展开始起作用。这个类调用了之前定义的用来解析文档注释的静态方法,并传入了它自身的文档注释,而且还将结果保存到几个受保护的成员变量中。最后,还在这个类中添加了几个访问器方法,一遍查看运行是否正常。有了DocumentReflection.php文件中代码。创建另外文件test.php例子测试DocumentingReflection类(test.php)Require_once(‘DocumentingReflection.php’);  Class demo{ /*  *这个方法是用于演示功能的。  *它引入了一个参数并且返回这个参数  *@param mixed $param1  一个返回的变量。  *$returns mixed 返回输入的变量*/Public function demoMethod($param1){ Return $param1;}}$reflector = new DocumentingReflectionMethod(‘demo’,’demoMethod’);$reflector->printDocTokens();Print_r($reflector->getParsedTags());Print_r($reflector->getParsedComments());运行结果如下:1=DOCBLOCK_NEWLINE=1=DOCBLOCK_NEWLINE= 2=DOCBLOCK_WHITESPACE=36=DOCBLOCK_TEXT=This method is for demonstration purposes.1=DOCBLOCK_NEWLINE= 1=DOCBLOCK_NEWLINE=2=DOCBLOCK_WHITESPACE=36=DOCBLOCK_TEXT=It takes a single parameter and returns it.1=DOCBLOCK_NEWLINE= 1=DOCBLOCK_NEWLINE= 2=DOCBLOCK_WHITESPACE=5=DOCBLOCK_TAG=@param36=DOCBLOCK_TEXT=mixed $param1 A variable to return.1=DOCBLOCK_NEWLINE= 2=DOCBLOCK_WHITESPACE=5=DOCBLOCK_TAG=@returns36=DOCBLOCK_TEXT=mixed The input variable is returned.1=DOCBLOCK_NEWLINE=结果:Array( [param]=>mixed $param1 A variable to return. [returns]=>mixed  The input variable is returned)Array(  [0]=>This method is for demonstration purposes  [1]=>It takes a single parameter and returns it.)下一步,需要为ReflectionParameter创建一个扩展类.如果没有与参数相关联的文档注 释,就需要从相关联方法的文档注释的param标签中获得参数数据。

4

要做到这一点,必须自定义ReflectionParameter以便从方法中获取数据,代码所示。 Public void ReflectionParameter::__construct(mixed function,mixed parameter);    值得注意的是,函数参数是混合类型的. 这个参数可能会被传入一个数据数组,其中包含了类名字符串或者对象实例以及方法名字符串。ReflectionParameter的代码。Class DocumentingReflectionParameter extends ReflectionParameter{  Protected $_reflectionMethod,$_reflectionClass,$_comment,$_type;  Public function __construct($method,$parameter){  Parent::__construct($method,$parameter);  $this->_comment=’’;  $this->_type =’undefined’;  $this->_reflectionMethod=new DocumentingflectionMethod($method[0],$method[1]);  $tags = $this->_reflectionMethod->getParsedTags();  If(array_key_exists(‘param’,$tags)){   $params = $tags[‘param’];  If(is_array($params)){   Foreach($params as $param){     If($this->_isParamTag($this->getName(),$param)){    $paramFound = $param;}}}else{ If($this->_isParamTag($this->getName(),$params)){  $paramFound = $params;}} If(isset($paramFound)){   $tokens = preg_split(‘/[\s\t]+/’,$paramFound,3);   $this->_comment = $cokens[2];   $this->_type = $tokens[0];}}}Public function getDeclaringFunction(){  Return $this->_reflectionMethod;} Public function getComment(){ Return $this->_comment;} Public function getType(){ Return $this->_type;} Private function _isParamTag($paramName,$paramData){  $paramSplit = preg_split(‘/[\s\t]+/’,$paramData,3);  $explodedName = trim($paramSplit[1],’$,.’); If($explodedName == $paramName){  Return ture;}else{  Return false;}}}    这个类比之前的类要复杂得多。这个类大多数的注释解析过程是在构造函数中实现的。    首先,需要构造这个类井调用父类的方法。如果没有相关联的文档注释,还需要给成员变量赋默认值。然后便可以开始处理过程了。

5

使用传递给构造函数的信息,对DocumentingReflectionMethod对象进行实例化。这个类使用getParsedTags()方法向你提供访问文档注释信息的功能。下一步,这段代码在$tags数组中查找是否存在’param’标签。如果存在,首先确定这个标签项是数组还是.单个的字符串值,从而做出相应的处理。    在这一过程中,这段代码还调用了私有成员函数_isParamTag()以确定参数是否是标签描述的那个,将paran标签分割为三部分,这个函数就可以确定这一点。分割是基于将字符串分解为标识符的一个正则表达式来完成的,用tab字符或者空格字符来对标识符进行分解。函数的第三个参数表示字符串只会被分割三次,这会形成一个拥有类型、变量名称和注释的数组。    然后,这段代码会检查变量名称项以确定它是否与ReflectionParameter类自身的名称相匹配.如果匹配。当前被检测的标签就属f那个参数。    一旦找到正确的标签,数据就会被分割开,并保存到受保护的成员变量_comment和_type中。之后,通过get函数访问这些数据。    现在,可以对这个类进行试用.如代码所示,实验DocumentingReflection的用法(Experiment.php)Require_once(‘DocumentingReflection.php’); Class demo{  /*  *@param string $param 这是一个注释*/Public function demoMethod($param=’test’){}} $refparam = new DocumentingReflectionParameter(array(   ‘demo’,’demoMethod’),    ‘param’);Var_dump($refparam->getComment());Var_dump($refparam->getType());运行会输出一下结果String(19)” this is the comment”String(6) “string”通常你不会希望提供太多信息去访问参数。我们来修改一下DocumentingReflectionMethod类,重写getParameters()函数,使它返回DocumentingReflectionParameter[],而不是ReflectionParameter[].在DocumentingReflectionMethod类中包含代码 Public function getParameters(){  $parameters =array();  If(is_object($this->_declaringClass)){    $class = get_class($this->_declaringClass);}else if(is_string($this->_declaringClass)){  $class = $this->_declaringClass;}Foreach(parent::getParameters() as $parameter){   $parameters[]= new DocumentingReflectionParameter(      Array($class,$this->getName()),         $parameter->getName());}Return $parameters;}这一方法首先检查在构造时保存的声明类,看它是对象还是字符串。因为在下一步操作中需要一个字符串,所以需要使用get_class()函数来检查对象的类型。   接着,需要调用父类的getParameters()方法。这个函数会返回ReflectionParameter对象的一个数组,而不是DocumentingReflectionParameter对象。这个函数的全部用途是用来挑用扩展的文档形式,而不是内置的形式。  为了测试重写的getParameters()函数,可以写如下代码Require_once(‘DocumentingReflection.php’); Class demo{ /** @param mixed $param1 第一个注释*$param string $param2  第二个注释*/Public function demoMethod($param1,$param2){}} $reflector = new DocumentingReflectionMethod(‘demo’,’demoMethod’);Foreach($reflector->getParameters() as $param){      Echo $param->getName().””;      Echo $param->getType().””;      Echo $param->getComment();      Echo “\n”;}运行结果:Param1 mixed The first commentParam2 string The second comment

6

现在你已经完成了扩展的方法和参数。那么如何完成类的扩展?DocumentingReflectionClass正是需要创建的下一个类。//创建DocumentingReflectionClass类(DocumentingReflection.php)Class DocumentingReflectionClass extends ReflectionClass{Protected $_Comments,$_tags,$_tokens; Public function __construct($class){  Parent::__construct($class);  $docComment = $this->getDocComment();  $parsedComment = DocumentingReflection::ParseDocComment($docComment);    $this->_comments = $parseComment[‘comments’];  $this->_tags = $parsedComment[‘tags’];   $this->_tokens = $parsedComment[‘tokens’];} Public function getMethods(){  $methods =array();Foreach(parent::getMethods() as $method){  $methods[] = new DocumentingReflectionMethod(   $this->getName90,$method->getName());}Return $methods;} Public function printDocTokens(){ Foreach($this->_tokens as $token){  Echo $token[0] .’=’;  Echo docblock_token_name[$token[0]].’=’;  Print_r($token[1]);  Echo ‘\n’;}} Public function getParseTags(){ Return $this->_tags;}Public function getParseComments(){ Return $this->_comments;} }

推荐信息