Symfony、Swoft 等框架的路由方式如果通过注释的方式是无法正确解析的,框架通过分析源码获得文件的命名空间,类名等信息,这些信息加密后都无法获得,验证方式:搜索框架源代码是否调用了 get_file_contents()、token_get_all() 等方法来解析 PHP源代码文件。

解决方案,参考 Drupal 加密

  • 模板 view 文件如果有模板引擎的特殊标签也无法支持,因为模板引擎需要分析 view 的内容来解析替换,如果加密了就无法分析了,只能通过黑名单的方式排除 不要加密 view

Doctrine 注解

Symfony ORM 框架 Doctrine 中存在file_get_contents()读取PHP源代码解析use语法的逻辑。使用Doctrine的项目加密后无法正确读取。例如easyswoole框架使用了Doctrine,在代码中使用注解时出现问题。

项目代码

namespace App\HttpController\Test;

use App\Annotation\Test\CheckAuth;

class Test extends Base
{
    /**
     * @CheckAuth(only_login = true)
     */
    function info() {
        return $this->success('请求成功');
    }
}

错误信息

[Semantical Error] The annotation "@CheckAuth" in method App\HttpController\Test\Auth::info() was never imported. Did you maybe forget to add a "use" statement for this annotation?
#0 /app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php(812): Doctrine\Common\Annotations\AnnotationException::semanticalError('The annotation ...')
#1 /app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php(726): Doctrine\Common\Annotations\DocParser->Annotation()
#2 /app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php(379): Doctrine\Common\Annotations\DocParser->Annotations()
#3 /app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php(217): Doctrine\Common\Annotations\DocParser->parse('/**\r\n     * @Ch...', 'method App\\Http...')
#4 /app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php(225): Doctrine\Common\Annotations\AnnotationReader->getMethodAnnotations(Object(ReflectionMethod))
#5 /app/App/HttpController/Test/Base.php(51): Doctrine\Common\Annotations\AnnotationReader->getMethodAnnotation(Object(ReflectionMethod), 'App\\Annotation\\...')
#6 /app/vendor/easyswoole/http/src/AbstractInterface/Controller.php(161): App\HttpController\Test\Base->onRequest('info')
#7 /app/vendor/easyswoole/http/src/AbstractInterface/Controller.php(153): EasySwoole\Http\AbstractInterface\Controller->__exec()
#8 /app/vendor/easyswoole/http/src/Dispatcher.php(229): EasySwoole\Http\AbstractInterface\Controller->__hook('info', Object(EasySwoole\Http\Request), Object(EasySwoole\Http\Response))
#9 /app/vendor/easyswoole/http/src/Dispatcher.php(183): EasySwoole\Http\Dispatcher->controllerExecutor(Object(EasySwoole\Http\Request), Object(EasySwoole\Http\Response), '/Test/auth/info')
#10 /app/vendor/easyswoole/easyswoole/src/Core.php(264): EasySwoole\Http\Dispatcher->dispatch(Object(EasySwoole\Http\Request), Object(EasySwoole\Http\Response))

AnnotationReader.php

class AnnotationReader implements Reader
{
// ...
    private function collectParsingMetadata($reflection): void
    {
        $type = $reflection instanceof ReflectionClass ? 'class' : 'function';
        $name = $reflection->getName();
    
        $ignoredAnnotationNames = self::$globalIgnoredNames;
        $annotations            = $this->preParser->parse($reflection->getDocComment(), $type . ' ' . $name);
    
        foreach ($annotations as $annotation) {
            if (! ($annotation instanceof IgnoreAnnotation)) {
                continue;
            }
    
            foreach ($annotation->names as $annot) {
                $ignoredAnnotationNames[$annot] = true;
            }
        }
    
        $this->imports[$type][$name] = array_merge(
            self::$globalImports,
            $this->phpParser->parseUseStatements($reflection),
            [
                '__NAMESPACE__' => $reflection->getNamespaceName(),
                'self' => $name,
            ]
        );
    
        $this->ignoredAnnotationNames[$type][$name] = $ignoredAnnotationNames;
    }
// ...
}

PhpParser.php

class PhpParser {
    // ...
    public function parseUseStatements($reflection): array
    {
        if (method_exists($reflection, 'getUseStatements')) {
            return $reflection->getUseStatements();
        }
    
        $filename = $reflection->getFileName();
    
        if ($filename === false) {
            return [];
        }
    
        $content = $this->getFileContent($filename, $reflection->getStartLine());
    
        if ($content === null) {
            return [];
        }
    
        $namespace = preg_quote($reflection->getNamespaceName());
        $content   = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
        $tokenizer = new TokenParser('<?php ' . $content);
    
        return $tokenizer->parseUseStatements($reflection->getNamespaceName());
    }
    // ...
}

解决方案

修改vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php,在$globalImports数组中手动添加所有需要use引入的类。


class AnnotationReader implements Reader
{
    private static $globalImports = [
        'ignoreannotation' => Annotation\IgnoreAnnotation::class,
        'checkauth' => \App\Annotation\Test\CheckAuth::class,
    ];

最后更新:2026-09-15