Verzeichnisstruktur phpBB-3.3.16


Veröffentlicht
27.04.2026

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Environment.php

Zuletzt modifiziert: 01.05.2026, 11:26 - Dateigröße: 28.06 KiB


 001  <?php
 002   
 003  /*
 004   * This file is part of Twig.
 005   *
 006   * (c) Fabien Potencier
 007   *
 008   * For the full copyright and license information, please view the LICENSE
 009   * file that was distributed with this source code.
 010   */
 011   
 012  namespace Twig;
 013   
 014  use Twig\Cache\CacheInterface;
 015  use Twig\Cache\FilesystemCache;
 016  use Twig\Cache\NullCache;
 017  use Twig\Error\Error;
 018  use Twig\Error\LoaderError;
 019  use Twig\Error\RuntimeError;
 020  use Twig\Error\SyntaxError;
 021  use Twig\Extension\CoreExtension;
 022  use Twig\Extension\EscaperExtension;
 023  use Twig\Extension\ExtensionInterface;
 024  use Twig\Extension\OptimizerExtension;
 025  use Twig\Loader\ArrayLoader;
 026  use Twig\Loader\ChainLoader;
 027  use Twig\Loader\LoaderInterface;
 028  use Twig\Node\ModuleNode;
 029  use Twig\Node\Node;
 030  use Twig\NodeVisitor\NodeVisitorInterface;
 031  use Twig\RuntimeLoader\RuntimeLoaderInterface;
 032  use Twig\TokenParser\TokenParserInterface;
 033   
 034  /**
 035   * Stores the Twig configuration and renders templates.
 036   *
 037   * @author Fabien Potencier <fabien@symfony.com>
 038   */
 039  class Environment
 040  {
 041      public const VERSION = '2.16.1';
 042      public const VERSION_ID = 21601;
 043      public const MAJOR_VERSION = 2;
 044      public const MINOR_VERSION = 16;
 045      public const RELEASE_VERSION = 1;
 046      public const EXTRA_VERSION = '';
 047   
 048      private $charset;
 049      private $loader;
 050      private $debug;
 051      private $autoReload;
 052      private $cache;
 053      private $lexer;
 054      private $parser;
 055      private $compiler;
 056      private $baseTemplateClass;
 057      private $globals = [];
 058      private $resolvedGlobals;
 059      private $loadedTemplates;
 060      private $strictVariables;
 061      private $templateClassPrefix = '__TwigTemplate_';
 062      private $originalCache;
 063      private $extensionSet;
 064      private $runtimeLoaders = [];
 065      private $runtimes = [];
 066      private $optionsHash;
 067   
 068      /**
 069       * Constructor.
 070       *
 071       * Available options:
 072       *
 073       *  * debug: When set to true, it automatically set "auto_reload" to true as
 074       *           well (default to false).
 075       *
 076       *  * charset: The charset used by the templates (default to UTF-8).
 077       *
 078       *  * base_template_class: The base template class to use for generated
 079       *                         templates (default to \Twig\Template).
 080       *
 081       *  * cache: An absolute path where to store the compiled templates,
 082       *           a \Twig\Cache\CacheInterface implementation,
 083       *           or false to disable compilation cache (default).
 084       *
 085       *  * auto_reload: Whether to reload the template if the original source changed.
 086       *                 If you don't provide the auto_reload option, it will be
 087       *                 determined automatically based on the debug value.
 088       *
 089       *  * strict_variables: Whether to ignore invalid variables in templates
 090       *                      (default to false).
 091       *
 092       *  * autoescape: Whether to enable auto-escaping (default to html):
 093       *                  * false: disable auto-escaping
 094       *                  * html, js: set the autoescaping to one of the supported strategies
 095       *                  * name: set the autoescaping strategy based on the template name extension
 096       *                  * PHP callback: a PHP callback that returns an escaping strategy based on the template "name"
 097       *
 098       *  * optimizations: A flag that indicates which optimizations to apply
 099       *                   (default to -1 which means that all optimizations are enabled;
 100       *                   set it to 0 to disable).
 101       */
 102      public function __construct(LoaderInterface $loader, $options = [])
 103      {
 104          $this->setLoader($loader);
 105   
 106          $options = array_merge([
 107              'debug' => false,
 108              'charset' => 'UTF-8',
 109              'base_template_class' => Template::class,
 110              'strict_variables' => false,
 111              'autoescape' => 'html',
 112              'cache' => false,
 113              'auto_reload' => null,
 114              'optimizations' => -1,
 115          ], $options);
 116   
 117          $this->debug = (bool) $options['debug'];
 118          $this->setCharset($options['charset']);
 119          $this->baseTemplateClass = '\\'.ltrim($options['base_template_class'], '\\');
 120          if ('\\'.Template::class !== $this->baseTemplateClass && '\Twig_Template' !== $this->baseTemplateClass) {
 121              @trigger_error('The "base_template_class" option on '.__CLASS__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED);
 122          }
 123          $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
 124          $this->strictVariables = (bool) $options['strict_variables'];
 125          $this->setCache($options['cache']);
 126          $this->extensionSet = new ExtensionSet();
 127   
 128          $this->addExtension(new CoreExtension());
 129          $this->addExtension(new EscaperExtension($options['autoescape']));
 130          $this->addExtension(new OptimizerExtension($options['optimizations']));
 131      }
 132   
 133      /**
 134       * Gets the base template class for compiled templates.
 135       *
 136       * @return string The base template class name
 137       */
 138      public function getBaseTemplateClass()
 139      {
 140          if (1 > \func_num_args() || \func_get_arg(0)) {
 141              @trigger_error('The '.__METHOD__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED);
 142          }
 143   
 144          return $this->baseTemplateClass;
 145      }
 146   
 147      /**
 148       * Sets the base template class for compiled templates.
 149       *
 150       * @param string $class The base template class name
 151       */
 152      public function setBaseTemplateClass($class)
 153      {
 154          @trigger_error('The '.__METHOD__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED);
 155   
 156          $this->baseTemplateClass = $class;
 157          $this->updateOptionsHash();
 158      }
 159   
 160      /**
 161       * Enables debugging mode.
 162       */
 163      public function enableDebug()
 164      {
 165          $this->debug = true;
 166          $this->updateOptionsHash();
 167      }
 168   
 169      /**
 170       * Disables debugging mode.
 171       */
 172      public function disableDebug()
 173      {
 174          $this->debug = false;
 175          $this->updateOptionsHash();
 176      }
 177   
 178      /**
 179       * Checks if debug mode is enabled.
 180       *
 181       * @return bool true if debug mode is enabled, false otherwise
 182       */
 183      public function isDebug()
 184      {
 185          return $this->debug;
 186      }
 187   
 188      /**
 189       * Enables the auto_reload option.
 190       */
 191      public function enableAutoReload()
 192      {
 193          $this->autoReload = true;
 194      }
 195   
 196      /**
 197       * Disables the auto_reload option.
 198       */
 199      public function disableAutoReload()
 200      {
 201          $this->autoReload = false;
 202      }
 203   
 204      /**
 205       * Checks if the auto_reload option is enabled.
 206       *
 207       * @return bool true if auto_reload is enabled, false otherwise
 208       */
 209      public function isAutoReload()
 210      {
 211          return $this->autoReload;
 212      }
 213   
 214      /**
 215       * Enables the strict_variables option.
 216       */
 217      public function enableStrictVariables()
 218      {
 219          $this->strictVariables = true;
 220          $this->updateOptionsHash();
 221      }
 222   
 223      /**
 224       * Disables the strict_variables option.
 225       */
 226      public function disableStrictVariables()
 227      {
 228          $this->strictVariables = false;
 229          $this->updateOptionsHash();
 230      }
 231   
 232      /**
 233       * Checks if the strict_variables option is enabled.
 234       *
 235       * @return bool true if strict_variables is enabled, false otherwise
 236       */
 237      public function isStrictVariables()
 238      {
 239          return $this->strictVariables;
 240      }
 241   
 242      /**
 243       * Gets the current cache implementation.
 244       *
 245       * @param bool $original Whether to return the original cache option or the real cache instance
 246       *
 247       * @return CacheInterface|string|false A Twig\Cache\CacheInterface implementation,
 248       *                                     an absolute path to the compiled templates,
 249       *                                     or false to disable cache
 250       */
 251      public function getCache($original = true)
 252      {
 253          return $original ? $this->originalCache : $this->cache;
 254      }
 255   
 256      /**
 257       * Sets the current cache implementation.
 258       *
 259       * @param CacheInterface|string|false $cache A Twig\Cache\CacheInterface implementation,
 260       *                                           an absolute path to the compiled templates,
 261       *                                           or false to disable cache
 262       */
 263      public function setCache($cache)
 264      {
 265          if (\is_string($cache)) {
 266              $this->originalCache = $cache;
 267              $this->cache = new FilesystemCache($cache, $this->autoReload ? FilesystemCache::FORCE_BYTECODE_INVALIDATION : 0);
 268          } elseif (false === $cache) {
 269              $this->originalCache = $cache;
 270              $this->cache = new NullCache();
 271          } elseif ($cache instanceof CacheInterface) {
 272              $this->originalCache = $this->cache = $cache;
 273          } else {
 274              throw new \LogicException('Cache can only be a string, false, or a \Twig\Cache\CacheInterface implementation.');
 275          }
 276      }
 277   
 278      /**
 279       * Gets the template class associated with the given string.
 280       *
 281       * The generated template class is based on the following parameters:
 282       *
 283       *  * The cache key for the given template;
 284       *  * The currently enabled extensions;
 285       *  * Whether the Twig C extension is available or not;
 286       *  * PHP version;
 287       *  * Twig version;
 288       *  * Options with what environment was created.
 289       *
 290       * @param string   $name  The name for which to calculate the template class name
 291       * @param int|null $index The index if it is an embedded template
 292       *
 293       * @return string The template class name
 294       *
 295       * @internal
 296       */
 297      public function getTemplateClass($name, $index = null)
 298      {
 299          $key = $this->getLoader()->getCacheKey($name).$this->optionsHash;
 300   
 301          return $this->templateClassPrefix.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index);
 302      }
 303   
 304      /**
 305       * Renders a template.
 306       *
 307       * @param string|TemplateWrapper $name    The template name
 308       * @param array                  $context An array of parameters to pass to the template
 309       *
 310       * @return string The rendered template
 311       *
 312       * @throws LoaderError  When the template cannot be found
 313       * @throws SyntaxError  When an error occurred during compilation
 314       * @throws RuntimeError When an error occurred during rendering
 315       */
 316      public function render($name, array $context = [])
 317      {
 318          return $this->load($name)->render($context);
 319      }
 320   
 321      /**
 322       * Displays a template.
 323       *
 324       * @param string|TemplateWrapper $name    The template name
 325       * @param array                  $context An array of parameters to pass to the template
 326       *
 327       * @throws LoaderError  When the template cannot be found
 328       * @throws SyntaxError  When an error occurred during compilation
 329       * @throws RuntimeError When an error occurred during rendering
 330       */
 331      public function display($name, array $context = [])
 332      {
 333          $this->load($name)->display($context);
 334      }
 335   
 336      /**
 337       * Loads a template.
 338       *
 339       * @param string|TemplateWrapper $name The template name
 340       *
 341       * @throws LoaderError  When the template cannot be found
 342       * @throws RuntimeError When a previously generated cache is corrupted
 343       * @throws SyntaxError  When an error occurred during compilation
 344       *
 345       * @return TemplateWrapper
 346       */
 347      public function load($name)
 348      {
 349          if ($name instanceof TemplateWrapper) {
 350              return $name;
 351          }
 352   
 353          if ($name instanceof Template) {
 354              @trigger_error('Passing a \Twig\Template instance to '.__METHOD__.' is deprecated since Twig 2.7.0, use \Twig\TemplateWrapper instead.', \E_USER_DEPRECATED);
 355   
 356              return new TemplateWrapper($this, $name);
 357          }
 358   
 359          return new TemplateWrapper($this, $this->loadTemplate($name));
 360      }
 361   
 362      /**
 363       * Loads a template internal representation.
 364       *
 365       * This method is for internal use only and should never be called
 366       * directly.
 367       *
 368       * @param string $name  The template name
 369       * @param int    $index The index if it is an embedded template
 370       *
 371       * @return Template A template instance representing the given template name
 372       *
 373       * @throws LoaderError  When the template cannot be found
 374       * @throws RuntimeError When a previously generated cache is corrupted
 375       * @throws SyntaxError  When an error occurred during compilation
 376       *
 377       * @internal
 378       */
 379      public function loadTemplate($name, $index = null)
 380      {
 381          return $this->loadClass($this->getTemplateClass($name), $name, $index);
 382      }
 383   
 384      /**
 385       * @internal
 386       */
 387      public function loadClass($cls, $name, $index = null)
 388      {
 389          $mainCls = $cls;
 390          if (null !== $index) {
 391              $cls .= '___'.$index;
 392          }
 393   
 394          if (isset($this->loadedTemplates[$cls])) {
 395              return $this->loadedTemplates[$cls];
 396          }
 397   
 398          if (!class_exists($cls, false)) {
 399              $key = $this->cache->generateKey($name, $mainCls);
 400   
 401              if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
 402                  $this->cache->load($key);
 403              }
 404   
 405              $source = null;
 406              if (!class_exists($cls, false)) {
 407                  $source = $this->getLoader()->getSourceContext($name);
 408                  $content = $this->compileSource($source);
 409                  $this->cache->write($key, $content);
 410                  $this->cache->load($key);
 411   
 412                  if (!class_exists($mainCls, false)) {
 413                      /* Last line of defense if either $this->bcWriteCacheFile was used,
 414                       * $this->cache is implemented as a no-op or we have a race condition
 415                       * where the cache was cleared between the above calls to write to and load from
 416                       * the cache.
 417                       */
 418                      eval('?>'.$content);
 419                  }
 420   
 421                  if (!class_exists($cls, false)) {
 422                      throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source);
 423                  }
 424              }
 425          }
 426   
 427          // to be removed in 3.0
 428          $this->extensionSet->initRuntime($this);
 429   
 430          return $this->loadedTemplates[$cls] = new $cls($this);
 431      }
 432   
 433      /**
 434       * Creates a template from source.
 435       *
 436       * This method should not be used as a generic way to load templates.
 437       *
 438       * @param string $template The template source
 439       * @param string $name     An optional name of the template to be used in error messages
 440       *
 441       * @return TemplateWrapper A template instance representing the given template name
 442       *
 443       * @throws LoaderError When the template cannot be found
 444       * @throws SyntaxError When an error occurred during compilation
 445       */
 446      public function createTemplate($template, string $name = null)
 447      {
 448          $hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $template, false);
 449          if (null !== $name) {
 450              $name = sprintf('%s (string template %s)', $name, $hash);
 451          } else {
 452              $name = sprintf('__string_template__%s', $hash);
 453          }
 454   
 455          $loader = new ChainLoader([
 456              new ArrayLoader([$name => $template]),
 457              $current = $this->getLoader(),
 458          ]);
 459   
 460          $this->setLoader($loader);
 461          try {
 462              return new TemplateWrapper($this, $this->loadTemplate($name));
 463          } finally {
 464              $this->setLoader($current);
 465          }
 466      }
 467   
 468      /**
 469       * Returns true if the template is still fresh.
 470       *
 471       * Besides checking the loader for freshness information,
 472       * this method also checks if the enabled extensions have
 473       * not changed.
 474       *
 475       * @param string $name The template name
 476       * @param int    $time The last modification time of the cached template
 477       *
 478       * @return bool true if the template is fresh, false otherwise
 479       */
 480      public function isTemplateFresh($name, $time)
 481      {
 482          return $this->extensionSet->getLastModified() <= $time && $this->getLoader()->isFresh($name, $time);
 483      }
 484   
 485      /**
 486       * Tries to load a template consecutively from an array.
 487       *
 488       * Similar to load() but it also accepts instances of \Twig\Template and
 489       * \Twig\TemplateWrapper, and an array of templates where each is tried to be loaded.
 490       *
 491       * @param string|TemplateWrapper|array $names A template or an array of templates to try consecutively
 492       *
 493       * @return TemplateWrapper|Template
 494       *
 495       * @throws LoaderError When none of the templates can be found
 496       * @throws SyntaxError When an error occurred during compilation
 497       */
 498      public function resolveTemplate($names)
 499      {
 500          if (!\is_array($names)) {
 501              $names = [$names];
 502          }
 503   
 504          $count = \count($names);
 505          foreach ($names as $name) {
 506              if ($name instanceof Template) {
 507                  return $name;
 508              }
 509              if ($name instanceof TemplateWrapper) {
 510                  return $name;
 511              }
 512   
 513              if (1 !== $count && !$this->getLoader()->exists($name)) {
 514                  continue;
 515              }
 516   
 517              return $this->loadTemplate($name);
 518          }
 519   
 520          throw new LoaderError(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
 521      }
 522   
 523      public function setLexer(Lexer $lexer)
 524      {
 525          $this->lexer = $lexer;
 526      }
 527   
 528      /**
 529       * Tokenizes a source code.
 530       *
 531       * @return TokenStream
 532       *
 533       * @throws SyntaxError When the code is syntactically wrong
 534       */
 535      public function tokenize(Source $source)
 536      {
 537          if (null === $this->lexer) {
 538              $this->lexer = new Lexer($this);
 539          }
 540   
 541          return $this->lexer->tokenize($source);
 542      }
 543   
 544      public function setParser(Parser $parser)
 545      {
 546          $this->parser = $parser;
 547      }
 548   
 549      /**
 550       * Converts a token stream to a node tree.
 551       *
 552       * @return ModuleNode
 553       *
 554       * @throws SyntaxError When the token stream is syntactically or semantically wrong
 555       */
 556      public function parse(TokenStream $stream)
 557      {
 558          if (null === $this->parser) {
 559              $this->parser = new Parser($this);
 560          }
 561   
 562          return $this->parser->parse($stream);
 563      }
 564   
 565      public function setCompiler(Compiler $compiler)
 566      {
 567          $this->compiler = $compiler;
 568      }
 569   
 570      /**
 571       * Compiles a node and returns the PHP code.
 572       *
 573       * @return string The compiled PHP source code
 574       */
 575      public function compile(Node $node)
 576      {
 577          if (null === $this->compiler) {
 578              $this->compiler = new Compiler($this);
 579          }
 580   
 581          return $this->compiler->compile($node)->getSource();
 582      }
 583   
 584      /**
 585       * Compiles a template source code.
 586       *
 587       * @return string The compiled PHP source code
 588       *
 589       * @throws SyntaxError When there was an error during tokenizing, parsing or compiling
 590       */
 591      public function compileSource(Source $source)
 592      {
 593          try {
 594              return $this->compile($this->parse($this->tokenize($source)));
 595          } catch (Error $e) {
 596              $e->setSourceContext($source);
 597              throw $e;
 598          } catch (\Exception $e) {
 599              throw new SyntaxError(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
 600          }
 601      }
 602   
 603      public function setLoader(LoaderInterface $loader)
 604      {
 605          $this->loader = $loader;
 606      }
 607   
 608      /**
 609       * Gets the Loader instance.
 610       *
 611       * @return LoaderInterface
 612       */
 613      public function getLoader()
 614      {
 615          return $this->loader;
 616      }
 617   
 618      /**
 619       * Sets the default template charset.
 620       *
 621       * @param string $charset The default charset
 622       */
 623      public function setCharset($charset)
 624      {
 625          if ('UTF8' === $charset = null === $charset ? null : strtoupper($charset)) {
 626              // iconv on Windows requires "UTF-8" instead of "UTF8"
 627              $charset = 'UTF-8';
 628          }
 629   
 630          $this->charset = $charset;
 631      }
 632   
 633      /**
 634       * Gets the default template charset.
 635       *
 636       * @return string The default charset
 637       */
 638      public function getCharset()
 639      {
 640          return $this->charset;
 641      }
 642   
 643      /**
 644       * Returns true if the given extension is registered.
 645       *
 646       * @param string $class The extension class name
 647       *
 648       * @return bool Whether the extension is registered or not
 649       */
 650      public function hasExtension($class)
 651      {
 652          return $this->extensionSet->hasExtension($class);
 653      }
 654   
 655      /**
 656       * Adds a runtime loader.
 657       */
 658      public function addRuntimeLoader(RuntimeLoaderInterface $loader)
 659      {
 660          $this->runtimeLoaders[] = $loader;
 661      }
 662   
 663      /**
 664       * Gets an extension by class name.
 665       *
 666       * @param string $class The extension class name
 667       *
 668       * @return ExtensionInterface
 669       */
 670      public function getExtension($class)
 671      {
 672          return $this->extensionSet->getExtension($class);
 673      }
 674   
 675      /**
 676       * Returns the runtime implementation of a Twig element (filter/function/test).
 677       *
 678       * @param string $class A runtime class name
 679       *
 680       * @return object The runtime implementation
 681       *
 682       * @throws RuntimeError When the template cannot be found
 683       */
 684      public function getRuntime($class)
 685      {
 686          if (isset($this->runtimes[$class])) {
 687              return $this->runtimes[$class];
 688          }
 689   
 690          foreach ($this->runtimeLoaders as $loader) {
 691              if (null !== $runtime = $loader->load($class)) {
 692                  return $this->runtimes[$class] = $runtime;
 693              }
 694          }
 695   
 696          throw new RuntimeError(sprintf('Unable to load the "%s" runtime.', $class));
 697      }
 698   
 699      public function addExtension(ExtensionInterface $extension)
 700      {
 701          $this->extensionSet->addExtension($extension);
 702          $this->updateOptionsHash();
 703      }
 704   
 705      /**
 706       * Registers an array of extensions.
 707       *
 708       * @param array $extensions An array of extensions
 709       */
 710      public function setExtensions(array $extensions)
 711      {
 712          $this->extensionSet->setExtensions($extensions);
 713          $this->updateOptionsHash();
 714      }
 715   
 716      /**
 717       * Returns all registered extensions.
 718       *
 719       * @return ExtensionInterface[] An array of extensions (keys are for internal usage only and should not be relied on)
 720       */
 721      public function getExtensions()
 722      {
 723          return $this->extensionSet->getExtensions();
 724      }
 725   
 726      public function addTokenParser(TokenParserInterface $parser)
 727      {
 728          $this->extensionSet->addTokenParser($parser);
 729      }
 730   
 731      /**
 732       * Gets the registered Token Parsers.
 733       *
 734       * @return TokenParserInterface[]
 735       *
 736       * @internal
 737       */
 738      public function getTokenParsers()
 739      {
 740          return $this->extensionSet->getTokenParsers();
 741      }
 742   
 743      /**
 744       * Gets registered tags.
 745       *
 746       * @return TokenParserInterface[]
 747       *
 748       * @internal
 749       */
 750      public function getTags()
 751      {
 752          $tags = [];
 753          foreach ($this->getTokenParsers() as $parser) {
 754              $tags[$parser->getTag()] = $parser;
 755          }
 756   
 757          return $tags;
 758      }
 759   
 760      public function addNodeVisitor(NodeVisitorInterface $visitor)
 761      {
 762          $this->extensionSet->addNodeVisitor($visitor);
 763      }
 764   
 765      /**
 766       * Gets the registered Node Visitors.
 767       *
 768       * @return NodeVisitorInterface[]
 769       *
 770       * @internal
 771       */
 772      public function getNodeVisitors()
 773      {
 774          return $this->extensionSet->getNodeVisitors();
 775      }
 776   
 777      public function addFilter(TwigFilter $filter)
 778      {
 779          $this->extensionSet->addFilter($filter);
 780      }
 781   
 782      /**
 783       * Get a filter by name.
 784       *
 785       * Subclasses may override this method and load filters differently;
 786       * so no list of filters is available.
 787       *
 788       * @param string $name The filter name
 789       *
 790       * @return TwigFilter|false
 791       *
 792       * @internal
 793       */
 794      public function getFilter($name)
 795      {
 796          return $this->extensionSet->getFilter($name);
 797      }
 798   
 799      public function registerUndefinedFilterCallback(callable $callable)
 800      {
 801          $this->extensionSet->registerUndefinedFilterCallback($callable);
 802      }
 803   
 804      /**
 805       * Gets the registered Filters.
 806       *
 807       * Be warned that this method cannot return filters defined with registerUndefinedFilterCallback.
 808       *
 809       * @return TwigFilter[]
 810       *
 811       * @see registerUndefinedFilterCallback
 812       *
 813       * @internal
 814       */
 815      public function getFilters()
 816      {
 817          return $this->extensionSet->getFilters();
 818      }
 819   
 820      public function addTest(TwigTest $test)
 821      {
 822          $this->extensionSet->addTest($test);
 823      }
 824   
 825      /**
 826       * Gets the registered Tests.
 827       *
 828       * @return TwigTest[]
 829       *
 830       * @internal
 831       */
 832      public function getTests()
 833      {
 834          return $this->extensionSet->getTests();
 835      }
 836   
 837      /**
 838       * Gets a test by name.
 839       *
 840       * @param string $name The test name
 841       *
 842       * @return TwigTest|false
 843       *
 844       * @internal
 845       */
 846      public function getTest($name)
 847      {
 848          return $this->extensionSet->getTest($name);
 849      }
 850   
 851      public function addFunction(TwigFunction $function)
 852      {
 853          $this->extensionSet->addFunction($function);
 854      }
 855   
 856      /**
 857       * Get a function by name.
 858       *
 859       * Subclasses may override this method and load functions differently;
 860       * so no list of functions is available.
 861       *
 862       * @param string $name function name
 863       *
 864       * @return TwigFunction|false
 865       *
 866       * @internal
 867       */
 868      public function getFunction($name)
 869      {
 870          return $this->extensionSet->getFunction($name);
 871      }
 872   
 873      public function registerUndefinedFunctionCallback(callable $callable)
 874      {
 875          $this->extensionSet->registerUndefinedFunctionCallback($callable);
 876      }
 877   
 878      /**
 879       * Gets registered functions.
 880       *
 881       * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
 882       *
 883       * @return TwigFunction[]
 884       *
 885       * @see registerUndefinedFunctionCallback
 886       *
 887       * @internal
 888       */
 889      public function getFunctions()
 890      {
 891          return $this->extensionSet->getFunctions();
 892      }
 893   
 894      /**
 895       * Registers a Global.
 896       *
 897       * New globals can be added before compiling or rendering a template;
 898       * but after, you can only update existing globals.
 899       *
 900       * @param string $name  The global name
 901       * @param mixed  $value The global value
 902       */
 903      public function addGlobal($name, $value)
 904      {
 905          if ($this->extensionSet->isInitialized() && !\array_key_exists($name, $this->getGlobals())) {
 906              throw new \LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
 907          }
 908   
 909          if (null !== $this->resolvedGlobals) {
 910              $this->resolvedGlobals[$name] = $value;
 911          } else {
 912              $this->globals[$name] = $value;
 913          }
 914      }
 915   
 916      /**
 917       * Gets the registered Globals.
 918       *
 919       * @return array An array of globals
 920       *
 921       * @internal
 922       */
 923      public function getGlobals()
 924      {
 925          if ($this->extensionSet->isInitialized()) {
 926              if (null === $this->resolvedGlobals) {
 927                  $this->resolvedGlobals = array_merge($this->extensionSet->getGlobals(), $this->globals);
 928              }
 929   
 930              return $this->resolvedGlobals;
 931          }
 932   
 933          return array_merge($this->extensionSet->getGlobals(), $this->globals);
 934      }
 935   
 936      /**
 937       * Merges a context with the defined globals.
 938       *
 939       * @param array $context An array representing the context
 940       *
 941       * @return array The context merged with the globals
 942       */
 943      public function mergeGlobals(array $context)
 944      {
 945          // we don't use array_merge as the context being generally
 946          // bigger than globals, this code is faster.
 947          foreach ($this->getGlobals() as $key => $value) {
 948              if (!\array_key_exists($key, $context)) {
 949                  $context[$key] = $value;
 950              }
 951          }
 952   
 953          return $context;
 954      }
 955   
 956      /**
 957       * Gets the registered unary Operators.
 958       *
 959       * @return array An array of unary operators
 960       *
 961       * @internal
 962       */
 963      public function getUnaryOperators()
 964      {
 965          return $this->extensionSet->getUnaryOperators();
 966      }
 967   
 968      /**
 969       * Gets the registered binary Operators.
 970       *
 971       * @return array An array of binary operators
 972       *
 973       * @internal
 974       */
 975      public function getBinaryOperators()
 976      {
 977          return $this->extensionSet->getBinaryOperators();
 978      }
 979   
 980      private function updateOptionsHash()
 981      {
 982          $this->optionsHash = implode(':', [
 983              $this->extensionSet->getSignature(),
 984              \PHP_MAJOR_VERSION,
 985              \PHP_MINOR_VERSION,
 986              self::VERSION,
 987              (int) $this->debug,
 988              $this->baseTemplateClass,
 989              (int) $this->strictVariables,
 990          ]);
 991      }
 992  }
 993   
 994  class_alias('Twig\Environment', 'Twig_Environment');
 995