okvpn / expression-language
基于twig语法的快速强大的PHP表达式语言
1.0.3
2024-09-14 11:34 UTC
Requires
- php: >=8.1
- twig/twig: ^2.7 || ^3.0
Requires (Dev)
- phpunit/phpunit: ^10.0
README
此库提供了安全评估表达式的接口,并将它们编译为原生PHP代码以提高性能。
用途
它是Symfony Expression Language的一个替代品,允许更多的操作,如for
、if
等。您可以实现任何逻辑并安全快速地执行它。我们从TWIG AST树中移除了PRINT_TOKEN
和TEXT_TOKEN
以防止输出,添加了return
语句,并进行了更多改进。
特性
- 允许执行脚本和评估表达式。
- 使用PhpStorm twig调试器功能进行调试。
- 支持所有twig特性,如sandbox、自定义扩展、标记、函数。
- 最小性能开销 - 比twig更快。
- 语法高亮已经集成到最流行的IDE中。
示例用法
基本评估示例
$lang = new TwigLanguage(options: ['cache' => __DIR__ . '/var/cache/twig']); $context = ['var1' => 10, 'users' => [1, 2, 5], 'user' => 1]; $lang->evaluate('user in users ? users|length + 1 : var1')
执行脚本
{% set msg = 'New sms' %} {% set newUsers = '' %} {% set usersList = [] %} {% set lastUserId = redis_get('sms-user') %} # redis_get - custom function {% for user in users %} {% if user > lastUserId %} {% set newUsers = newUsers ~ user ~ ' ' %} {% do redis_set('sms-user', user, 0) %} {% set usersList[_key] = user %} # allow set to array {% endif %} {% endfor %} {% if newUsers is not empty %} {% do telegram_send('chart111', msg ~ "\n" ~ newUsers|trim) %} # telegram_send - custom function {% endif %} {% return usersList %} # new return token
$lang = new TwigLanguage(); $script = <<<TXT ... {% return 10 + 15 %} TXT; var_dump($lang->execute($script, $context)); // execute with template $loader = new \Twig\Loader\FilesystemLoader(__DIR__ . '/scripts'); $lang = new TwigLanguage(loader: $loader); var_dump($lang->execute('test22.twig', $context));
evaluate
方法 - 比使用 execute
更快,因为我们跳过了额外的异常处理和错误逻辑。此外,evaluate
可以接受没有 {%
标记的代码。
基准测试
我们使用以下测试来比较Symfony Expression Language和此库之间的开销
$lang = new TwigLanguage(options: [ 'cache' => __DIR__ . '/var/cache/twig', 'auto_reload' => true, ]); $expr = 'user == 1 ? var1 + var2 : var1 + 1'; $lang->evaluate($expr, $context); // Symfony EL $sf = new ExpressionLanguage(); $expression = $sf->parse($expr, array_keys($context)); $sf->evaluate($expression, $context); // Native PHP $fn = static function ($context) { return $context['user'] === 1 ? $context['var1'] + $context['var2'] : $context['var1'] + 1; }; $t1 = microtime(true); for ($i = 0; $i < 200000; $i++) { // comment line where needed $result = $fn($context); $result = $sf->evaluate($expression, $context); $result = $lang->evaluate($expr, $context); } echo (microtime(true) - $t1)/200000 * 1000000 . "\n";
扩展和sandbox模式。
结果
许可证
MIT许可证。