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

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 $cache;
  23.     private $lexer;
  24.     private $parser;
  25.     private $compiler;
  26.     protected $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.      * @param Expression|string $expression The expression to compile
  42.      *
  43.      * @return string The compiled PHP source code
  44.      */
  45.     public function compile($expression, array $names = [])
  46.     {
  47.         return $this->getCompiler()->compile($this->parse($expression$names)->getNodes())->getSource();
  48.     }
  49.     /**
  50.      * Evaluate an expression.
  51.      *
  52.      * @param Expression|string $expression The expression to compile
  53.      *
  54.      * @return mixed The result of the evaluation of the expression
  55.      */
  56.     public function evaluate($expression, array $values = [])
  57.     {
  58.         return $this->parse($expressionarray_keys($values))->getNodes()->evaluate($this->functions$values);
  59.     }
  60.     /**
  61.      * Parses an expression.
  62.      *
  63.      * @param Expression|string $expression The expression to parse
  64.      *
  65.      * @return ParsedExpression A ParsedExpression instance
  66.      */
  67.     public function parse($expression, array $names)
  68.     {
  69.         if ($expression instanceof ParsedExpression) {
  70.             return $expression;
  71.         }
  72.         asort($names);
  73.         $cacheKeyItems = [];
  74.         foreach ($names as $nameKey => $name) {
  75.             $cacheKeyItems[] = \is_int($nameKey) ? $name $nameKey.':'.$name;
  76.         }
  77.         $cacheItem $this->cache->getItem(rawurlencode($expression.'//'.implode('|'$cacheKeyItems)));
  78.         if (null === $parsedExpression $cacheItem->get()) {
  79.             $nodes $this->getParser()->parse($this->getLexer()->tokenize((string) $expression), $names);
  80.             $parsedExpression = new ParsedExpression((string) $expression$nodes);
  81.             $cacheItem->set($parsedExpression);
  82.             $this->cache->save($cacheItem);
  83.         }
  84.         return $parsedExpression;
  85.     }
  86.     /**
  87.      * Validates the syntax of an expression.
  88.      *
  89.      * @param Expression|string $expression The expression to validate
  90.      * @param array|null        $names      The list of acceptable variable names in the expression, or null to accept any names
  91.      *
  92.      * @throws SyntaxError When the passed expression is invalid
  93.      */
  94.     public function lint($expression, ?array $names): void
  95.     {
  96.         if ($expression instanceof ParsedExpression) {
  97.             return;
  98.         }
  99.         $this->getParser()->lint($this->getLexer()->tokenize((string) $expression), $names);
  100.     }
  101.     /**
  102.      * Registers a function.
  103.      *
  104.      * @param callable $compiler  A callable able to compile the function
  105.      * @param callable $evaluator A callable able to evaluate the function
  106.      *
  107.      * @throws \LogicException when registering a function after calling evaluate(), compile() or parse()
  108.      *
  109.      * @see ExpressionFunction
  110.      */
  111.     public function register(string $name, callable $compiler, callable $evaluator)
  112.     {
  113.         if (null !== $this->parser) {
  114.             throw new \LogicException('Registering functions after calling evaluate(), compile() or parse() is not supported.');
  115.         }
  116.         $this->functions[$name] = ['compiler' => $compiler'evaluator' => $evaluator];
  117.     }
  118.     public function addFunction(ExpressionFunction $function)
  119.     {
  120.         $this->register($function->getName(), $function->getCompiler(), $function->getEvaluator());
  121.     }
  122.     public function registerProvider(ExpressionFunctionProviderInterface $provider)
  123.     {
  124.         foreach ($provider->getFunctions() as $function) {
  125.             $this->addFunction($function);
  126.         }
  127.     }
  128.     protected function registerFunctions()
  129.     {
  130.         $this->addFunction(ExpressionFunction::fromPhp('constant'));
  131.     }
  132.     private function getLexer(): Lexer
  133.     {
  134.         if (null === $this->lexer) {
  135.             $this->lexer = new Lexer();
  136.         }
  137.         return $this->lexer;
  138.     }
  139.     private function getParser(): Parser
  140.     {
  141.         if (null === $this->parser) {
  142.             $this->parser = new Parser($this->functions);
  143.         }
  144.         return $this->parser;
  145.     }
  146.     private function getCompiler(): Compiler
  147.     {
  148.         if (null === $this->compiler) {
  149.             $this->compiler = new Compiler($this->functions);
  150.         }
  151.         return $this->compiler->reset();
  152.     }
  153. }