Расширение ExpressionLanguage

Расширение ExpressionLanguage

ExpressionLanguage может быть расширен путём добавление пользовательских функций. Например, в фреймворке Symfony, безопасность имеет настраиваемые функции для проверки роли пользователя.

Note

Если вы хотите узнать, как использовать функции в выражении, см. "".

Регистрация функций

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

Для того, чтобы зарегистрировать функцию, используйте register(). Этот метод имеет 3 аргумента:

  • name - Имя функции в выражении;
  • compiler - Функция, выполняемая при компиляции выражения, использующего функцию;
  • evaluator - Функция, выполняемая при оценке выражения.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;

$expressionLanguage = new ExpressionLanguage();
$expressionLanguage->register('lowercase', function ($str) {
    return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str);
}, function ($arguments, $str) {
    if (!is_string($str)) {
        return $str;
    }

    return strtolower($str);
});

var_dump($expressionLanguage->evaluate('lowercase("HELLO")'));
// это выведет: hello

В дополнение к пользовательским аргументам функции, evaluator передатся переменная arguments в качестве первого аргумента, который эквивалентен второму аргументу compile() (например, "значения" при оценке выражения).

Использование поставщиков выражений

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

Этот интерфес требует одного метода: getFunctions(), который возвращает массив функций выражения (экземпляры ExpressionFunction) для регистрации:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;

class StringExpressionLanguageProvider implements ExpressionFunctionProviderInterface
{
    public function getFunctions()
    {
        return array(
            new ExpressionFunction('lowercase', function ($str) {
                return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str);
            }, function ($arguments, $str) {
                if (!is_string($str)) {
                    return $str;
                }

                return strtolower($str);
            }),
        );
    }
}

Tip

Чтобы создать функцию выражения из PHP функции со статическим методом fromPhp():

1
ExpressionFunction::fromPhp('strtoupper');

Функции с пространством имён поддерживаются, но они требуют второго аргумента для определения имени выражения:

1
ExpressionFunction::fromPhp('My\strtoupper', 'my_strtoupper');

Вы можете зарегистрировать поставщика, используя registerProvider() или используя второй аргумент конструктора:

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;

// использование конструктора
$expressionLanguage = new ExpressionLanguage(null, array(
    new StringExpressionLanguageProvider(),
    // ...
));

// использование registerProvider()
$expressionLanguage->registerProvider(new StringExpressionLanguageProvider());

Tip

Рекомендуется создать ваш собственный класс ExpressionLanguage в вашей библиотеке. Теперь вы можете добавлять выражение, переопределяя конструктор:

1
2
3
4
5
6
7
8
9
10
11
12
13
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage;

class ExpressionLanguage extends BaseExpressionLanguage
{
    public function __construct(CacheItemPoolInterface $parser = null, array $providers = array())
    {
        // добавляет к поставщику по умолчанию, чтобы позволить пользователем легко его переопределять
        array_unshift($providers, new StringExpressionLanguageProvider());

        parent::__construct($parser, $providers);
    }
}