3

我正在尝试使用 preg_match 解析 PHPDoc 标签,但我遇到了一些负面的后视问题。我以前从未使用过这些,但我的理解是它们被用作排除项。

这是我的模式:

/\*\*.+?(?<! \*/)@access public.+? \*/\s+?function\s+[a-zA-Z0-9_]+\(

这是我试图解析的示例 PHP 文件:

<?php

/**
 * This is the shortcut to DIRECTORY_SEPARATOR
 */
defined('DS') or define('DS',DIRECTORY_SEPARATOR);

/**
 * Foo
 * 
 * @return bool
 * @access public
 */
function foo()
{
    return true;
}

我想用@access public 标记匹配任何函数,但在这种情况下,匹配从 DS 常量的注释开始。我认为(?<! \*/)会排除它与 DS 评论的结束评论标签匹配。

我错过了什么?

4

3 回答 3

3

在@bishop的链接之后,我找到了一个对我有用的使用负前瞻的示例。

我变了

.+?(?<! \*/)

(?:(?! \*/).)+?

所以现在的完整模式是:

/\*\*(?:(?! \*/).)+?@access public.+? \*/\s+?function\s+[a-zA-Z0-9_]+\(

编辑:

也匹配函数类型和参数的完整模式:

(?<full>[\t ]*?/\*\*(?:(?! \*/).)+?@access public(?:(?! \*/).)+? \*/\s+?(?:public |protected |private )??(?:static )??function\s+[a-zA-Z0-9_]+\(.*?\))

和类匹配:

(?<full>(?<indent>[\t ]*?)/\*\*(?:(?! \*/).)+?@access public.+? \*/\s+?(?:abstract )??class\s+[a-zA-Z0-9_]+\s??.*?{)

于 2014-01-29T01:37:14.343 回答
0

负后视必须是固定长度。听起来你会更好地使用某种 DocBlock 解析器。有许多可用的解决方案。

于 2014-01-29T01:26:14.330 回答
0

具有以下token_get_all()功能:

$tokens = token_get_all($code);
$result = array();

foreach ($tokens as $k=>$token) {
    switch ($token[0]):
        case T_DOC_COMMENT:
            $isPublic = strpos($token[1], '@access public');
            break;

        case T_FUNCTION:
            $isFunction = true;
            break;

        case T_WHITESPACE:
            break;

        case T_STRING:
            if ($isFunction && $isPublic) $result[] = $token[1];

        default:
            $isFunction = false;
    endswitch;
}    

print_r($result);

要了解您可以使用标记器提取的内容,我建议您将以下代码放入 foreach 循环中,位于endswitch;

if ($isPublic && isset($token[1]))
    printf("%s\t%s\t%s\n", $token[0],
                           token_name($token[0]),
                           strtr($token[1], "\n", ' ')
                           ); 
于 2014-01-29T03:04:04.573 回答