Розширення ExpressionLanguage

Дата оновлення перекладу 2022-11-12

Розширення 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 [
            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, [
    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);
    }
}