将 PHP 文档注释解析为数据结构

2022-08-30 14:49:39

我正在使用PHP中的Reflectle API从方法中提取DocComment(PHPDoc)字符串

$r = new ReflectionMethod($object);
$comment = $r->getDocComment();

这将返回一个如下所示的字符串(取决于该方法的记录程度)

/**
* Does this great things
*
* @param string $thing
* @return Some_Great_Thing
*/

是否有任何内置方法或函数可以将 PHP Doc 注释字符串解析为数据结构?

$object = some_magic_function_or_method($comment_string);

echo 'Returns a: ', $object->return;

缺乏这一点,PHPDoc源代码的哪一部分我应该自己看。

缺乏和/或除此之外,是否有第三方代码被认为比PHPDoc代码“更好”?

我意识到解析这些字符串不是火箭科学,甚至不是计算机科学,但我更喜欢一个经过良好测试的库/例程/方法,它是为了处理许多可能存在于野外的混乱,半不正确的PHP Doc代码而构建的。


答案 1

我很惊讶这还没有被提及:使用zend Framework的Zend_Reflection呢?这可能会派上用场,特别是如果您使用基于Zend Framework构建的软件,例如Magento。

有关一些代码示例,请参阅 Zend 框架手册,有关可用方法,请参阅 API 文档

有不同的方法可以做到这一点:

  • 将文件名传递给Zend_Reflection_File。
  • 将对象传递给Zend_Reflection_Class。
  • 将对象和方法名称传递给Zend_Reflection_Method。
  • 如果您手头真的只有注释字符串,您甚至可以将小型虚拟类的代码放在一起,将其保存到临时文件中,然后将该文件传递给Zend_Reflection_File。

让我们来看一个简单的案例,并假设你有一个要检查的现有类。

代码是这样的(未经测试,请原谅我):

$method = new Zend_Reflection_Method($class, 'yourMethod');
$docblock = $method->getDocBlock();

if ($docBlock->hasTag('return')) {
    $tagReturn = $docBlock->getTag('return'); // $tagReturn is an instance of Zend_Reflection_Docblock_Tag_Return
    echo "Returns a: " . $tagReturn->getType() . "<br>";
    echo "Comment for return type: " . $tagReturn->getDescription();
}

答案 2

您可以使用Fabien Potencier Sami(“Yet Another PHP API Documentation Generator”)开源项目中的“DocBlockParser”类。
首先,从GitHub获取Sami。
这是如何使用它的一个示例:

<?php

require_once 'Sami/Parser/DocBlockParser.php';
require_once 'Sami/Parser/Node/DocBlockNode.php';

class TestClass {
    /**
     * This is the short description.
     *  
     * This is the 1st line of the long description 
     * This is the 2nd line of the long description 
     * This is the 3rd line of the long description   
     *  
     * @param bool|string $foo sometimes a boolean, sometimes a string (or, could have just used "mixed")
     * @param bool|int $bar sometimes a boolean, sometimes an int (again, could have just used "mixed") 
     * @return string de-html_entitied string (no entities at all)
     */
    public function another_test($foo, $bar) {
        return strtr($foo,array_flip(get_html_translation_table(HTML_ENTITIES)));
    }
}

use Sami\Parser\DocBlockParser;
use Sami\Parser\Node\DocBlockNode;

try {
    $method = new ReflectionMethod('TestClass', 'another_test');
    $comment = $method->getDocComment();
    if ($comment !== FALSE) {
        $dbp = new DocBlockParser();
        $doc = $dbp->parse($comment);
        echo "\n** getDesc:\n";
        print_r($doc->getDesc());
        echo "\n** getTags:\n";
        print_r($doc->getTags());
        echo "\n** getTag('param'):\n";
        print_r($doc->getTag('param'));
        echo "\n** getErrors:\n";
        print_r($doc->getErrors());
        echo "\n** getOtherTags:\n";
        print_r($doc->getOtherTags());
        echo "\n** getShortDesc:\n";
        print_r($doc->getShortDesc());
        echo "\n** getLongDesc:\n";
        print_r($doc->getLongDesc());
    }
} catch (Exception $e) {
    print_r($e);
}

?>

这是测试页面的输出:

** getDesc:
This is the short description.

This is the 1st line of the long description 
This is the 2nd line of the long description 
This is the 3rd line of the long description
** getTags:
Array
(
    [param] => Array
        (
            [0] => Array
                (
                    [0] => Array
                        (
                            [0] => Array
                                (
                                    [0] => bool
                                    [1] => 
                                )

                            [1] => Array
                                (
                                    [0] => string
                                    [1] => 
                                )

                        )

                    [1] => foo
                    [2] => sometimes a boolean, sometimes a string (or, could have just used "mixed")
                )

            [1] => Array
                (
                    [0] => Array
                        (
                            [0] => Array
                                (
                                    [0] => bool
                                    [1] => 
                                )

                            [1] => Array
                                (
                                    [0] => int
                                    [1] => 
                                )

                        )

                    [1] => bar
                    [2] => sometimes a boolean, sometimes an int (again, could have just used "mixed")
                )

        )

    [return] => Array
        (
            [0] => Array
                (
                    [0] => Array
                        (
                            [0] => Array
                                (
                                    [0] => string
                                    [1] => 
                                )

                        )

                    [1] => de-html_entitied string (no entities at all)
                )

        )

)

** getTag('param'):
Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [0] => Array
                        (
                            [0] => bool
                            [1] => 
                        )

                    [1] => Array
                        (
                            [0] => string
                            [1] => 
                        )

                )

            [1] => foo
            [2] => sometimes a boolean, sometimes a string (or, could have just used "mixed")
        )

    [1] => Array
        (
            [0] => Array
                (
                    [0] => Array
                        (
                            [0] => bool
                            [1] => 
                        )

                    [1] => Array
                        (
                            [0] => int
                            [1] => 
                        )

                )

            [1] => bar
            [2] => sometimes a boolean, sometimes an int (again, could have just used "mixed")
        )

)

** getErrors:
Array
(
)

** getOtherTags:
Array
(
)

** getShortDesc:
This is the short description.
** getLongDesc:
This is the 1st line of the long description 
This is the 2nd line of the long description 
This is the 3rd line of the long description

推荐