ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] # 注解解析器 这是第一次用C语言为PHP世界编写注解解析器组件。`Phalcon\Annotations`是一个通用组件,可以在PHP类中轻松解析和缓存注解,以便在应用程序中使用。 从类,方法和属性中的docblock读取注解。注解可以放在docblock中的任何位置: ```php <?php /** * This is the class description * * @AmazingClass(true) */ class Example { /** * This a property with a special feature * * @SpecialFeature */ protected $someProperty; /** * This is a method * * @SpecialFeature */ public function someMethod() { // ... } } ``` 注解具有以下语法: ```php /** * @Annotation-Name * @Annotation-Name(param1, param2, ...) */ ``` 此外,注解可以放在docblock的任何部分: ```php <?php /** * This a property with a special feature * * @SpecialFeature * * More comments * * @AnotherSpecialFeature(true) */ ``` 解析器非常灵活,以下docblock有效: ```php <?php /** * This a property with a special feature @SpecialFeature({ someParameter='the value', false }) More comments @AnotherSpecialFeature(true) @MoreAnnotations **/ ``` 但是,为了使代码更易于维护和理解,建议在docblock的末尾放置注解: ```php <?php /** * This a property with a special feature * More comments * * @SpecialFeature({someParameter='the value', false}) * @AnotherSpecialFeature(true) */ ``` ## 工厂 有许多可用的注解适配器(请参阅适配器)。您使用的那个将取决于您的应用程序的需求。实例化这种适配器的传统方法如下: ```php <?php use Phalcon\Annotations\Adapter\Memory as MemoryAdapter; $reader = new MemoryAdapter(); // ..... ``` 但是,您也可以使用工厂方法来实现相同的目的: ```php <?php use Phalcon\Annotations\Factory; $options = [ 'prefix' => 'annotations', 'lifetime' => '3600', 'adapter' => 'memory', // Load the Memory adapter ]; $annotations = Factory::load($options); ``` 在处理从配置文件中实例化注解适配器时,Factory加载程序提供了更大的灵活性。 ## 阅读注解 实现反射器以使用面向对象的接口轻松获取在类上定义的注解: ```php <?php use Phalcon\Annotations\Adapter\Memory as MemoryAdapter; $reader = new MemoryAdapter(); // Reflect the annotations in the class Example $reflector = $reader->get('Example'); // Read the annotations in the class' docblock $annotations = $reflector->getClassAnnotations(); // Traverse the annotations foreach ($annotations as $annotation) { // Print the annotation name echo $annotation->getName(), PHP_EOL; // Print the number of arguments echo $annotation->numberArguments(), PHP_EOL; // Print the arguments print_r($annotation->getArguments()); } ``` 注解读取过程非常快,但出于性能原因,建议使用适配器存储解析的注解。适配器缓存已处理的注解,无需一次又一次地解析注解。 在上面的示例中使用了`Phalcon\Annotations\Adapter\Memory` 。此适配器仅在请求运行时缓存注解,因此适配器更适合开发。当应用程序处于生产阶段时,还有其他适配器可以换出。 ## 注解的类型 注解可能有参数或没有。参数可以是简单的文字(字符串,数字,布尔值,空),数组,散列列表或其他注解: ```php <?php /** * Simple Annotation * * @SomeAnnotation */ /** * Annotation with parameters * * @SomeAnnotation('hello', 'world', 1, 2, 3, false, true) */ /** * Annotation with named parameters * * @SomeAnnotation(first='hello', second='world', third=1) * @SomeAnnotation(first: 'hello', second: 'world', third: 1) */ /** * Passing an array * * @SomeAnnotation([1, 2, 3, 4]) * @SomeAnnotation({1, 2, 3, 4}) */ /** * Passing a hash as parameter * * @SomeAnnotation({first=1, second=2, third=3}) * @SomeAnnotation({'first'=1, 'second'=2, 'third'=3}) * @SomeAnnotation({'first': 1, 'second': 2, 'third': 3}) * @SomeAnnotation(['first': 1, 'second': 2, 'third': 3]) */ /** * Nested arrays/hashes * * @SomeAnnotation({'name'='SomeName', 'other'={ * 'foo1': 'bar1', 'foo2': 'bar2', {1, 2, 3}, * }}) */ /** * Nested Annotations * * @SomeAnnotation(first=@AnotherAnnotation(1, 2, 3)) */ ``` ## 实际用途 接下来我们将解释PHP应用程序中注解的一些实际示例: ### 带注解的缓存启动器 让我们假设我们已经创建了以下控制器,并且您希望创建一个插件,如果执行的最后一个操作被标记为可缓存,则会自动启动缓存。首先,我们在Dispatcher服务中注册一个插件,以便在执行路由时得到通知: ```php <?php use Phalcon\Mvc\Dispatcher as MvcDispatcher; use Phalcon\Events\Manager as EventsManager; $di['dispatcher'] = function () { $eventsManager = new EventsManager(); // Attach the plugin to 'dispatch' events $eventsManager->attach( 'dispatch', new CacheEnablerPlugin() ); $dispatcher = new MvcDispatcher(); $dispatcher->setEventsManager($eventsManager); return $dispatcher; }; ``` `CacheEnablerPlugin` 是一个插件,它拦截调度程序中执行的每个操作,如果需要,启用缓存: ```php <?php use Phalcon\Events\Event; use Phalcon\Mvc\Dispatcher; use Phalcon\Mvc\User\Plugin; /** * Enables the cache for a view if the latest * executed action has the annotation @Cache */ class CacheEnablerPlugin extends Plugin { /** * This event is executed before every route is executed in the dispatcher */ public function beforeExecuteRoute(Event $event, Dispatcher $dispatcher) { // Parse the annotations in the method currently executed $annotations = $this->annotations->getMethod( $dispatcher->getControllerClass(), $dispatcher->getActiveMethod() ); // Check if the method has an annotation 'Cache' if ($annotations->has('Cache')) { // The method has the annotation 'Cache' $annotation = $annotations->get('Cache'); // Get the lifetime $lifetime = $annotation->getNamedParameter('lifetime'); $options = [ 'lifetime' => $lifetime, ]; // Check if there is a user defined cache key if ($annotation->hasNamedParameter('key')) { $options['key'] = $annotation->getNamedParameter('key'); } // Enable the cache for the current method $this->view->cache($options); } } } ``` 现在,我们可以在控制器中使用注解: ```php <?php use Phalcon\Mvc\Controller; class NewsController extends Controller { public function indexAction() { } /** * This is a comment * * @Cache(lifetime=86400) */ public function showAllAction() { $this->view->article = Articles::find(); } /** * This is a comment * * @Cache(key='my-key', lifetime=86400) */ public function showAction($slug) { $this->view->article = Articles::findFirstByTitle($slug); } } ``` ### 带注解的私人/公共区域 您可以使用注解告诉ACL哪些控制器属于管理区域: ```php <?php use Phalcon\Acl; use Phalcon\Acl\Role; use Phalcon\Acl\Resource; use Phalcon\Events\Event; use Phalcon\Mvc\User\Plugin; use Phalcon\Mvc\Dispatcher; use Phalcon\Acl\Adapter\Memory as AclList; /** * This is the security plugin which controls that users only have access to the modules they're assigned to */ class SecurityAnnotationsPlugin extends Plugin { /** * This action is executed before execute any action in the application * * @param Event $event * @param Dispatcher $dispatcher * * @return bool */ public function beforeDispatch(Event $event, Dispatcher $dispatcher) { // Possible controller class name $controllerName = $dispatcher->getControllerClass(); // Possible method name $actionName = $dispatcher->getActiveMethod(); // Get annotations in the controller class $annotations = $this->annotations->get($controllerName); // The controller is private? if ($annotations->getClassAnnotations()->has('Private')) { // Check if the session variable is active? if (!$this->session->get('auth')) { // The user is no logged redirect to login $dispatcher->forward( [ 'controller' => 'session', 'action' => 'login', ] ); return false; } } // Continue normally return true; } } ``` ## 注解适配器 该组件使用适配器来缓存或不缓存已解析和处理的注解,从而提高性能或为开发/测试提供便利: | 类 | 描述 | | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Phalcon\Annotations\Adapter\Memory` | 注解仅缓存在内存中。当请求结束时,清除缓存,重新加载每个请求中的注解。此适配器适用于开发阶段 | | `Phalcon\Annotations\Adapter\Files` | 经过解析和处理的注解将永久存储在PHP文件中,从而提高性能。此适配器必须与字节码缓存一起使用。 | | `Phalcon\Annotations\Adapter\Apc` | 经过解析和处理的注解会永久存储在APC高速缓存中,从而提高性能。这是更快的适配器 | | `Phalcon\Annotations\Adapter\Xcache` | 经过解析和处理的注解会永久存储在XCache缓存中,从而提高性能。这也是一个快速适配器 | ### 实现自己的适配器 必须实现`Phalcon\Annotations\AdapterInterface`接口才能创建自己的注解适配器或扩展现有注解适配器。 ## 外部资源 * [教程:使用Annotations创建自定义模型的初始化程序](https://blog.phalconphp.com/post/tutorial-creating-a-custom-models-initializer)