vendor/symfony/expression-language/ExpressionLanguage.php line 40

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\ExpressionLanguage;
  11. use Psr\Cache\CacheItemPoolInterface;
  12. use Symfony\Component\Cache\Adapter\ArrayAdapter;
  13. // Help opcache.preload discover always-needed symbols
  14. class_exists(ParsedExpression::class);
  15. /**
  16.  * Allows to compile and evaluate expressions written in your own DSL.
  17.  *
  18.  * @author Fabien Potencier <fabien@symfony.com>
  19.  */
  20. class ExpressionLanguage
  21. {
  22.     private CacheItemPoolInterface $cache;
  23.     private Lexer $lexer;
  24.     private Parser $parser;
  25.     private Compiler $compiler;
  26.     protected array $functions = [];
  27.     /**
  28.      * @param ExpressionFunctionProviderInterface[] $providers
  29.      */
  30.     public function __construct(CacheItemPoolInterface $cache null, array $providers = [])
  31.     {
  32.         $this->cache $cache ?? new ArrayAdapter();
  33.         $this->registerFunctions();
  34.         foreach ($providers as $provider) {
  35.             $this->registerProvider($provider);
  36.         }
  37.     }
  38.     /**
  39.      * Compiles an expression source code.
  40.      */
  41.     public function compile(Expression|string $expression, array $names = []): string
  42.     {
  43.         return $this->getCompiler()->compile($this->parse($expression$names)->getNodes())->getSource();
  44.     }
  45.     /**
  46.      * Evaluate an expression.
  47.      */
  48.     public function evaluate(Expression|string $expression, array $values = []): mixed
  49.     {
  50.         return $this->parse($expressionarray_keys($values))->getNodes()->evaluate($this->functions$values);
  51.     }
  52.     /**
  53.      * Parses an expression.
  54.      */
  55.     public function parse(Expression|string $expression, array $names): ParsedExpression
  56.     {
  57.         if ($expression instanceof ParsedExpression) {
  58.             return $expression;
  59.         }
  60.         asort($names);
  61.         $cacheKeyItems = [];
  62.         foreach ($names as $nameKey => $name) {
  63.             $cacheKeyItems[] = \is_int($nameKey) ? $name $nameKey.':'.$name;
  64.         }
  65.         $cacheItem $this->cache->getItem(rawurlencode($expression.'//'.implode('|'$cacheKeyItems)));
  66.         if (null === $parsedExpression $cacheItem->get()) {
  67.             $nodes $this->getParser()->parse($this->getLexer()->tokenize((string) $expression), $names);
  68.             $parsedExpression = new ParsedExpression((string) $expression$nodes);
  69.             $cacheItem->set($parsedExpression);
  70.             $this->cache->save($cacheItem);
  71.         }
  72.         return $parsedExpression;
  73.     }
  74.     /**
  75.      * Validates the syntax of an expression.
  76.      *
  77.      * @param array|null $names The list of acceptable variable names in the expression, or null to accept any names
  78.      *
  79.      * @throws SyntaxError When the passed expression is invalid
  80.      */
  81.     public function lint(Expression|string $expression, ?array $names): void
  82.     {
  83.         if ($expression instanceof ParsedExpression) {
  84.             return;
  85.         }
  86.         $this->getParser()->lint($this->getLexer()->tokenize((string) $expression), $names);
  87.     }
  88.     /**
  89.      * Registers a function.
  90.      *
  91.      * @param callable $compiler  A callable able to compile the function
  92.      * @param callable $evaluator A callable able to evaluate the function
  93.      *
  94.      * @throws \LogicException when registering a function after calling evaluate(), compile() or parse()
  95.      *
  96.      * @see ExpressionFunction
  97.      */
  98.     public function register(string $name, callable $compiler, callable $evaluator)
  99.     {
  100.         if (isset($this->parser)) {
  101.             throw new \LogicException('Registering functions after calling evaluate(), compile() or parse() is not supported.');
  102.         }
  103.         $this->functions[$name] = ['compiler' => $compiler'evaluator' => $evaluator];
  104.     }
  105.     public function addFunction(ExpressionFunction $function)
  106.     {
  107.         $this->register($function->getName(), $function->getCompiler(), $function->getEvaluator());
  108.     }
  109.     public function registerProvider(ExpressionFunctionProviderInterface $provider)
  110.     {
  111.         foreach ($provider->getFunctions() as $function) {
  112.             $this->addFunction($function);
  113.         }
  114.     }
  115.     protected function registerFunctions()
  116.     {
  117.         $this->addFunction(ExpressionFunction::fromPhp('constant'));
  118.     }
  119.     private function getLexer(): Lexer
  120.     {
  121.         return $this->lexer ??= new Lexer();
  122.     }
  123.     private function getParser(): Parser
  124.     {
  125.         return $this->parser ??= new Parser($this->functions);
  126.     }
  127.     private function getCompiler(): Compiler
  128.     {
  129.         $this->compiler ??= new Compiler($this->functions);
  130.         return $this->compiler->reset();
  131.     }
  132. }