duanqin9507 2014-07-03 09:51
浏览 45
已采纳

php注释,命名空间和使用关键字

I am writing an annotation parser for php (I cannot used any 3rd party ones due to specific needs) and I took sympfony2 code as an inspiration

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;

As I can see here we define ORM in use statement and then somehow the annotation parser knows that ORM is an alias to Doctrine\ORM\Mapping.

My ultimate goal is to be able to pass class names as aliases into my annotations

use some/namespace/Enum;
use another/ns/PropEnum;

class Abc
{
   /**
    * @Enum(PropEnum)
    **/
   protected $prop;
}

Could you please point me towards the right direction as I do not even know where to start?

Thanks

  • 写回答

1条回答 默认 最新

  • duandian8110 2014-07-03 11:27
    关注

    Let's take a look at how doctrine/annotations (the package used by Symfony) solves this problem.

    The PhpParser parses the PHP file of the class (which you can get by ReflectionClass#getFilename()). Let's look at the parseClass() method line by line:

    if (method_exists($class, 'getUseStatements')) {
        return $class->getUseStatements();
    }
    

    Doctrine has a custom StaticReflectionClass class which already has a getUseStatements() method to get the use statements in the class file. I assume you don't use that class, so let's move on!

    if (false === $filename = $class->getFilename()) {
        return array();
    }
    
    $content = $this->getFileContent($filename, $class->getStartLine());
    
    if (null === $content) {
        return array();
    }
    

    These statements retrieve the file content of the class. If there was no content or no file, there are also no use statements.

    $namespace = preg_quote($class->getNamespaceName());
    $content = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
    

    Here they are looking for the line that defines the namespace for the class in the file. It'll be followed by the use statements, so the regex just extracts the namespace and everything that follows it.

    $tokenizer = new TokenParser('<?php ' . $content);
    
    $statements = $tokenizer->parseUseStatements($class->getNamespaceName());
    
    return $statements;
    

    Then it creates a TokenParser class with only that content in it and let it find the use statements in it.

    If you look at the TokenParser, you'll find that it uses token_get_all() to transform the file into PHP tokens used by the PHP engine and then just moves through that token tree looking for T_USE statements, which it extracts and saves.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?