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

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

Annotations are read from docblocks in classes, methods and properties. An annotation can be placed at any position in the docblock:

<?php

/**
 * Это специальное свойство
 *
 * @AmazingClass(true)
 */
class Example
{
    /**
     * Это свойство с особенностью
     *
     * @SpecialFeature
     */
    protected $someProperty;

    /**
     * Это метод
     *
     * @SpecialFeature
     */
    public function someMethod()
    {
        // ...
    }
}

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

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

Аннотации также могут быть помещены в любую часть блока документации:

<?php

/**
 * Это специальное свойство
 *
 * @SpecialFeature
 *
 * Еще комментарии
 *
 * @AnotherSpecialFeature(true)
 */

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

<?php

/**
 * Это специальное свойство @SpecialFeature({
someParameter='the value', false

 })  Еще комментарии @AnotherSpecialFeature(true) @MoreAnnotations
 **/

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

<?php

/**
 * Это специальное свойство
 * Еще комментарии
 *
 * @SpecialFeature({someParameter='the value', false})
 * @AnotherSpecialFeature(true)
 */

Фабрика

Существует множество адаптеров аннотаций (см. Адаптеры). Используемый вами, будет зависеть от нужд вашего приложения. Традиционный способ инициализации экземпляра адаптера выглядит следующим образом:

<?php

use Phalcon\Annotations\Adapter\Memory as MemoryAdapter;

$reader = new MemoryAdapter();

// .....

Однако, вы можете использовать фабричный метод, чтобы достигнуть того же самого:

<?php

use Phalcon\Annotations\Factory;

$options = [
    'prefix'   => 'annotations',
    'lifetime' => '3600',
    'adapter'  => 'memory',      // Загрузка Memory адаптера
];

$annotations = Factory::load($options);

Фабричный загрузчик обеспечивает большую гибкость, при создании экземпляров адаптеров аннотаций из конфигурационных файлов.

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

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

<?php

use Phalcon\Annotations\Adapter\Memory as MemoryAdapter;

$reader = new MemoryAdapter();

// Отразить аннотации в классе Example
$reflector = $reader->get('Example');

// Прочесть аннотации в блоке документации класса
$annotations = $reflector->getClassAnnotations();

// Произвести обход всех аннотаций
foreach ($annotations as $annotation) {
    // Вывести название аннотации
    echo $annotation->getName(), PHP_EOL;

    // Вывести количество аргументов
    echo $annotation->numberArguments(), PHP_EOL;

    // Вывести аргументы
    print_r($annotation->getArguments());
}

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

В примере выше был использован Phalcon\Annotations\Adapter\Memory. Этот адаптер кэширует аннотации только в процессе работы, поэтому он более подходит для разработки. Существуют и другие адаптеры, которые можно использовать в промышленной эксплуатации.

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

Annotations may have parameters or not. A parameter could be a simple literal (strings, number, boolean, null), an array, a hashed list or other annotation:

<?php

/**
 * Простая аннотация
 *
 * @SomeAnnotation
 */

/**
 * Аннотация с параметрами
 *
 * @SomeAnnotation('hello', 'world', 1, 2, 3, false, true)
 */

/**
 * Аннотация с именованными параметрами
 *
 * @SomeAnnotation(first='hello', second='world', third=1)
 * @SomeAnnotation(first: 'hello', second: 'world', third: 1)
 */

/**
 * Передача массива
 *
 * @SomeAnnotation([1, 2, 3, 4])
 * @SomeAnnotation({1, 2, 3, 4})
 */

/**
 * Передача хеша в качестве параметра
 *
 * @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])
 */

/**
 * Вложенные массивы/хеши
 *
 * @SomeAnnotation({'name'='SomeName', 'other'={
 *     'foo1': 'bar1', 'foo2': 'bar2', {1, 2, 3},
 * }})
 */

/**
 * Вложенные аннотации
 *
 * @SomeAnnotation([email protected](1, 2, 3))
 */

Практическое использование

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

Кэширование с помощью аннотаций

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

<?php

use Phalcon\Mvc\Dispatcher as MvcDispatcher;
use Phalcon\Events\Manager as EventsManager;

$di['dispatcher'] = function () {
    $eventsManager = new EventsManager();

    // Привязать плагин к событию 'dispatch'
    $eventsManager->attach(
        'dispatch',
        new CacheEnablerPlugin()
    );

    $dispatcher = new MvcDispatcher();

    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
};

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

<?php

use Phalcon\Events\Event;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\User\Plugin;

/**
 * Включение кэша для представления, если
 * последнее запущенное действие имело аннотацию @Cache
 */
class CacheEnablerPlugin extends Plugin
{
    /**
     * Это событие запускается перед запуском каждого маршрута в диспетчере
     */
    public function beforeExecuteRoute(Event $event, Dispatcher $dispatcher)
    {
        // Разбор аннотаций в текущем запущенном методе
        $annotations = $this->annotations->getMethod(
            $dispatcher->getControllerClass(),
            $dispatcher->getActiveMethod()
        );

        // Проверить, имеет ли метод аннотацию 'Cache'
        if ($annotations->has('Cache')) {
            // Метод имеет аннотацию 'Cache'
            $annotation = $annotations->get('Cache');

            // Получить время жизни кэша
            $lifetime = $annotation->getNamedParameter('lifetime');

            $options = [
                'lifetime' => $lifetime,
            ];

            // Проверить, есть ли определенный пользователем ключ кэша
            if ($annotation->hasNamedParameter('key')) {
                $options['key'] = $annotation->getNamedParameter('key');
            }

            // Включить кэш для текущего метода
            $this->view->cache($options);
        }
    }
}

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

<?php

use Phalcon\Mvc\Controller;

class NewsController extends Controller
{
    public function indexAction()
    {

    }

    /**
     * Это комментарий
     *
     * @Cache(lifetime=86400)
     */
    public function showAllAction()
    {
        $this->view->article = Articles::find();
    }

    /**
     * Это комментарий
     *
     * @Cache(key='my-key', lifetime=86400)
     */
    public function showAction($slug)
    {
        $this->view->article = Articles::findFirstByTitle($slug);
    }
}

Контроль доступа и аннотации

Вы можете использовать аннотации для того, чтобы сообщить ACL механизму какие контроллеры являются закрытыми для публичного доступа:

<?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;

/**
 * Это плагин безопастности, который контролирует,
 * что пользователи имеют доступ только к разрешенным модулям
 */
class SecurityAnnotationsPlugin extends Plugin
{
    /**
     * Этот метод будет вызван перед выполнением любого действия контроллера 
     *
     * @param Event $event
     * @param Dispatcher $dispatcher
     *
     * @return bool
     */
    public function beforeDispatch(Event $event, Dispatcher $dispatcher)
    {
        // Название класса контроллера
        $controllerName = $dispatcher->getControllerClass();

        // Название метода
        $actionName = $dispatcher->getActiveMethod();

        // Получаем аннотации из класса контроллера
        $annotations = $this->annotations->get($controllerName);

        // Является ли контроллер приватным?
        if ($annotations->getClassAnnotations()->has('Private')) {
            // Проверяем аутентификацию с использованием сессии
            if (!$this->session->get('auth')) {

                // Пользователь не авторизован, перенаправляем на /login
                $dispatcher->forward(
                    [
                        'controller' => 'session',
                        'action'     => 'login',
                    ]
                );

                return false;
            }
        }

        // Continue normally
        return true;
    }
}

Адаптеры аннотаций

Компонент поддерживает адаптеры с возможностью кэширования проанализированных аннотаций. Это позволяет увеличивать производительность в боевом режиме и моментальное обновление данных при разработке и тестировании:

Класс Описание
Phalcon\Annotations\Adapter\Memory The annotations are cached only in memory. When the request ends the cache is cleaned reloading the annotations in each request. This adapter is suitable for a development stage
Phalcon\Annotations\Adapter\Files Parsed and processed annotations are stored permanently in PHP files improving performance. This adapter must be used together with a bytecode cache.
Phalcon\Annotations\Adapter\Apc Parsed and processed annotations are stored permanently in the APC cache improving performance. This is the faster adapter
Phalcon\Annotations\Adapter\Xcache Parsed and processed annotations are stored permanently in the XCache cache improving performance. This is a fast adapter too

Реализация собственных адаптеров

Для создания своего адаптера необходимо реализовать интерфейс Phalcon\Annotations\AdapterInterface, или использовать наследование от существующего адаптера.

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

Explore All Topics