我正在为php编写一个注释解析器(由于特定需要,我不能使用任何第三方解析器)并且我将sympfony2代码作为灵感来源
namespace Acme\StoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="product")
*/
class Product
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
正如我在这里看到的,我们在use语句中定义ORM然后以某种方式注释解析器知道ORM是Doctrine \ ORM \ Mapping的别名。
我的最终目标是能够将类名作为别名传递到我的注释中
use some/namespace/Enum;
use another/ns/PropEnum;
class Abc
{
/**
* @Enum(PropEnum)
**/
protected $prop;
}
请你指出我正确的方向,因为我甚至不知道从哪里开始?
由于
答案 0 :(得分:3)
让我们来看看doctrine/annotations
(Symfony使用的包)如何解决这个问题。
PhpParser
解析类的PHP文件(可以通过ReflectionClass#getFilename()
获得)。让我们逐行查看parseClass()
方法:
if (method_exists($class, 'getUseStatements')) {
return $class->getUseStatements();
}
Doctrine有一个自定义StaticReflectionClass
类,它已经有一个getUseStatements()
方法来获取类文件中的use语句。我假设你没有使用那个课程,所以让我们继续前进!
if (false === $filename = $class->getFilename()) {
return array();
}
$content = $this->getFileContent($filename, $class->getStartLine());
if (null === $content) {
return array();
}
这些语句检索类的文件内容。如果没有内容或没有文件,也没有使用声明。
$namespace = preg_quote($class->getNamespaceName());
$content = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
在这里,他们正在寻找定义文件中类的命名空间的行。接下来是use语句,因此正则表达式只提取命名空间及其后的所有内容。
$tokenizer = new TokenParser('<?php ' . $content);
$statements = $tokenizer->parseUseStatements($class->getNamespaceName());
return $statements;
然后它创建一个TokenParser
类,其中只包含该内容,并让它在其中找到use语句。
如果查看TokenParser
,您会发现它使用token_get_all()
将文件转换为PHP引擎使用的PHP令牌,然后只需移动该令牌树查找{{ 1}}语句,它提取并保存。