Spec-Zone.ru › Phalcon 3

Парсер аннотаций

Впервые компонент парсера аннотаций написан на C для мира PHP. Phalcon\Annotations — это компонент общего назначения, который обеспечивает лёгкость парсинга и кэширования аннотаций в классах PHP для использования в приложениях.

Аннотации считываются из docblock в классах, методах и свойствах. Аннотация может быть размещена в любом месте docblock:

/**
 * 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()
    {
        // ...
    }
}

Синтаксис аннотации следующий:

/**
 * @Annotation-Name
 * @Annotation-Name(param1, param2, ...)
 */

Также аннотация может быть размещена в любой части docblock:

/**
 * This a property with a special feature
 *
 * @SpecialFeature
 *
 * More comments
 *
 * @AnotherSpecialFeature(true)
 */

Парсер очень гибкий, следующий docblock является допустимым:

/**
 * This a property with a special feature @SpecialFeature({
someParameter="the value", false

 })  More comments @AnotherSpecialFeature(true) @MoreAnnotations
 **/

Однако, для повышения читаемости и поддерживаемости кода рекомендуется размещать аннотации в конце docblock:

/**
 * This a property with a special feature
 * More comments
 *
 * @SpecialFeature({someParameter="the value", false})
 * @AnotherSpecialFeature(true)
 */

Чтение аннотаций

Рефлектор реализован для лёгкого получения аннотаций, определённых в классе, с использованием объектно-ориентированного интерфейса:

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 был использован в приведённом выше примере. Этот адаптер кэширует аннотации только во время выполнения запроса, и поэтому он более подходит для разработки. Есть и другие адаптеры для использования в производственной среде.

Типы аннотаций

Аннотации могут иметь параметры или нет. Параметр может быть простым литералом (строки, числа, булевы значения, null), массивом, хэшированным списком или другой аннотацией:

/**
 * 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([email protected](1, 2, 3))
 */

Практическое применение

Далее мы объясним несколько практических примеров использования аннотаций в приложениях PHP:

Включение кэша с помощью аннотаций

Предположим, мы создали следующий контроллер, и вы хотите создать плагин, который автоматически запускает кэш, если последнее выполненное действие помечено как кэшируемое. Прежде всего, мы регистрируем плагин в службе Dispatcher, чтобы уведомлять о выполнении маршрута:

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 — это плагин, который перехватывает каждое выполняемое действие в диспетчере, включая кэш при необходимости:

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);
        }
    }
}

Теперь мы можем использовать аннотацию в контроллере:

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, какие контроллеры относятся к административным областям:

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
     */
    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.

Внешние ресурсы

  • Учебник: Создание пользовательского инициализатора моделей с помощью аннотаций

© 2011–2017 Phalcon Framework Team
Licensed under the Creative Commons Attribution License 3.0.
https://docs.phalconphp.com/en/latest/reference/annotations.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API