vendor/twig/twig/lib/Twig/Environment.php line 289

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Twig.
  4.  *
  5.  * (c) Fabien Potencier
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. /**
  11.  * Stores the Twig configuration.
  12.  *
  13.  * @author Fabien Potencier <fabien@symfony.com>
  14.  */
  15. class Twig_Environment
  16. {
  17.     const VERSION '2.4.8';
  18.     const VERSION_ID 20408;
  19.     const MAJOR_VERSION 2;
  20.     const MINOR_VERSION 4;
  21.     const RELEASE_VERSION 8;
  22.     const EXTRA_VERSION '';
  23.     private $charset;
  24.     private $loader;
  25.     private $debug;
  26.     private $autoReload;
  27.     private $cache;
  28.     private $lexer;
  29.     private $parser;
  30.     private $compiler;
  31.     private $baseTemplateClass;
  32.     private $globals = array();
  33.     private $resolvedGlobals;
  34.     private $loadedTemplates;
  35.     private $strictVariables;
  36.     private $templateClassPrefix '__TwigTemplate_';
  37.     private $originalCache;
  38.     private $extensionSet;
  39.     private $runtimeLoaders = array();
  40.     private $runtimes = array();
  41.     private $optionsHash;
  42.     private $loading = array();
  43.     /**
  44.      * Constructor.
  45.      *
  46.      * Available options:
  47.      *
  48.      *  * debug: When set to true, it automatically set "auto_reload" to true as
  49.      *           well (default to false).
  50.      *
  51.      *  * charset: The charset used by the templates (default to UTF-8).
  52.      *
  53.      *  * base_template_class: The base template class to use for generated
  54.      *                         templates (default to Twig_Template).
  55.      *
  56.      *  * cache: An absolute path where to store the compiled templates,
  57.      *           a Twig_Cache_Interface implementation,
  58.      *           or false to disable compilation cache (default).
  59.      *
  60.      *  * auto_reload: Whether to reload the template if the original source changed.
  61.      *                 If you don't provide the auto_reload option, it will be
  62.      *                 determined automatically based on the debug value.
  63.      *
  64.      *  * strict_variables: Whether to ignore invalid variables in templates
  65.      *                      (default to false).
  66.      *
  67.      *  * autoescape: Whether to enable auto-escaping (default to html):
  68.      *                  * false: disable auto-escaping
  69.      *                  * html, js: set the autoescaping to one of the supported strategies
  70.      *                  * name: set the autoescaping strategy based on the template name extension
  71.      *                  * PHP callback: a PHP callback that returns an escaping strategy based on the template "name"
  72.      *
  73.      *  * optimizations: A flag that indicates which optimizations to apply
  74.      *                   (default to -1 which means that all optimizations are enabled;
  75.      *                   set it to 0 to disable).
  76.      *
  77.      * @param Twig_LoaderInterface $loader
  78.      * @param array                $options An array of options
  79.      */
  80.     public function __construct(Twig_LoaderInterface $loader$options = array())
  81.     {
  82.         $this->setLoader($loader);
  83.         $options array_merge(array(
  84.             'debug' => false,
  85.             'charset' => 'UTF-8',
  86.             'base_template_class' => 'Twig_Template',
  87.             'strict_variables' => false,
  88.             'autoescape' => 'html',
  89.             'cache' => false,
  90.             'auto_reload' => null,
  91.             'optimizations' => -1,
  92.         ), $options);
  93.         $this->debug = (bool) $options['debug'];
  94.         $this->setCharset($options['charset']);
  95.         $this->baseTemplateClass $options['base_template_class'];
  96.         $this->autoReload null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
  97.         $this->strictVariables = (bool) $options['strict_variables'];
  98.         $this->setCache($options['cache']);
  99.         $this->extensionSet = new Twig_ExtensionSet();
  100.         $this->addExtension(new Twig_Extension_Core());
  101.         $this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
  102.         $this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
  103.     }
  104.     /**
  105.      * Gets the base template class for compiled templates.
  106.      *
  107.      * @return string The base template class name
  108.      */
  109.     public function getBaseTemplateClass()
  110.     {
  111.         return $this->baseTemplateClass;
  112.     }
  113.     /**
  114.      * Sets the base template class for compiled templates.
  115.      *
  116.      * @param string $class The base template class name
  117.      */
  118.     public function setBaseTemplateClass($class)
  119.     {
  120.         $this->baseTemplateClass $class;
  121.         $this->updateOptionsHash();
  122.     }
  123.     /**
  124.      * Enables debugging mode.
  125.      */
  126.     public function enableDebug()
  127.     {
  128.         $this->debug true;
  129.         $this->updateOptionsHash();
  130.     }
  131.     /**
  132.      * Disables debugging mode.
  133.      */
  134.     public function disableDebug()
  135.     {
  136.         $this->debug false;
  137.         $this->updateOptionsHash();
  138.     }
  139.     /**
  140.      * Checks if debug mode is enabled.
  141.      *
  142.      * @return bool true if debug mode is enabled, false otherwise
  143.      */
  144.     public function isDebug()
  145.     {
  146.         return $this->debug;
  147.     }
  148.     /**
  149.      * Enables the auto_reload option.
  150.      */
  151.     public function enableAutoReload()
  152.     {
  153.         $this->autoReload true;
  154.     }
  155.     /**
  156.      * Disables the auto_reload option.
  157.      */
  158.     public function disableAutoReload()
  159.     {
  160.         $this->autoReload false;
  161.     }
  162.     /**
  163.      * Checks if the auto_reload option is enabled.
  164.      *
  165.      * @return bool true if auto_reload is enabled, false otherwise
  166.      */
  167.     public function isAutoReload()
  168.     {
  169.         return $this->autoReload;
  170.     }
  171.     /**
  172.      * Enables the strict_variables option.
  173.      */
  174.     public function enableStrictVariables()
  175.     {
  176.         $this->strictVariables true;
  177.         $this->updateOptionsHash();
  178.     }
  179.     /**
  180.      * Disables the strict_variables option.
  181.      */
  182.     public function disableStrictVariables()
  183.     {
  184.         $this->strictVariables false;
  185.         $this->updateOptionsHash();
  186.     }
  187.     /**
  188.      * Checks if the strict_variables option is enabled.
  189.      *
  190.      * @return bool true if strict_variables is enabled, false otherwise
  191.      */
  192.     public function isStrictVariables()
  193.     {
  194.         return $this->strictVariables;
  195.     }
  196.     /**
  197.      * Gets the current cache implementation.
  198.      *
  199.      * @param bool $original Whether to return the original cache option or the real cache instance
  200.      *
  201.      * @return Twig_CacheInterface|string|false A Twig_CacheInterface implementation,
  202.      *                                          an absolute path to the compiled templates,
  203.      *                                          or false to disable cache
  204.      */
  205.     public function getCache($original true)
  206.     {
  207.         return $original $this->originalCache $this->cache;
  208.     }
  209.     /**
  210.      * Sets the current cache implementation.
  211.      *
  212.      * @param Twig_CacheInterface|string|false $cache A Twig_CacheInterface implementation,
  213.      *                                                an absolute path to the compiled templates,
  214.      *                                                or false to disable cache
  215.      */
  216.     public function setCache($cache)
  217.     {
  218.         if (is_string($cache)) {
  219.             $this->originalCache $cache;
  220.             $this->cache = new Twig_Cache_Filesystem($cache);
  221.         } elseif (false === $cache) {
  222.             $this->originalCache $cache;
  223.             $this->cache = new Twig_Cache_Null();
  224.         } elseif ($cache instanceof Twig_CacheInterface) {
  225.             $this->originalCache $this->cache $cache;
  226.         } else {
  227.             throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.'));
  228.         }
  229.     }
  230.     /**
  231.      * Gets the template class associated with the given string.
  232.      *
  233.      * The generated template class is based on the following parameters:
  234.      *
  235.      *  * The cache key for the given template;
  236.      *  * The currently enabled extensions;
  237.      *  * Whether the Twig C extension is available or not;
  238.      *  * PHP version;
  239.      *  * Twig version;
  240.      *  * Options with what environment was created.
  241.      *
  242.      * @param string   $name  The name for which to calculate the template class name
  243.      * @param int|null $index The index if it is an embedded template
  244.      *
  245.      * @return string The template class name
  246.      */
  247.     public function getTemplateClass($name$index null)
  248.     {
  249.         $key $this->getLoader()->getCacheKey($name).$this->optionsHash;
  250.         return $this->templateClassPrefix.hash('sha256'$key).(null === $index '' '_'.$index);
  251.     }
  252.     /**
  253.      * Renders a template.
  254.      *
  255.      * @param string $name    The template name
  256.      * @param array  $context An array of parameters to pass to the template
  257.      *
  258.      * @return string The rendered template
  259.      *
  260.      * @throws Twig_Error_Loader  When the template cannot be found
  261.      * @throws Twig_Error_Syntax  When an error occurred during compilation
  262.      * @throws Twig_Error_Runtime When an error occurred during rendering
  263.      */
  264.     public function render($name, array $context = array())
  265.     {
  266.         return $this->loadTemplate($name)->render($context);
  267.     }
  268.     /**
  269.      * Displays a template.
  270.      *
  271.      * @param string $name    The template name
  272.      * @param array  $context An array of parameters to pass to the template
  273.      *
  274.      * @throws Twig_Error_Loader  When the template cannot be found
  275.      * @throws Twig_Error_Syntax  When an error occurred during compilation
  276.      * @throws Twig_Error_Runtime When an error occurred during rendering
  277.      */
  278.     public function display($name, array $context = array())
  279.     {
  280.         $this->loadTemplate($name)->display($context);
  281.     }
  282.     /**
  283.      * Loads a template.
  284.      *
  285.      * @param string|Twig_TemplateWrapper|Twig_Template $name The template name
  286.      *
  287.      * @throws Twig_Error_Loader  When the template cannot be found
  288.      * @throws Twig_Error_Runtime When a previously generated cache is corrupted
  289.      * @throws Twig_Error_Syntax  When an error occurred during compilation
  290.      *
  291.      * @return Twig_TemplateWrapper
  292.      */
  293.     public function load($name)
  294.     {
  295.         if ($name instanceof Twig_TemplateWrapper) {
  296.             return $name;
  297.         }
  298.         if ($name instanceof Twig_Template) {
  299.             return new Twig_TemplateWrapper($this$name);
  300.         }
  301.         return new Twig_TemplateWrapper($this$this->loadTemplate($name));
  302.     }
  303.     /**
  304.      * Loads a template internal representation.
  305.      *
  306.      * This method is for internal use only and should never be called
  307.      * directly.
  308.      *
  309.      * @param string $name  The template name
  310.      * @param int    $index The index if it is an embedded template
  311.      *
  312.      * @return Twig_Template A template instance representing the given template name
  313.      *
  314.      * @throws Twig_Error_Loader  When the template cannot be found
  315.      * @throws Twig_Error_Runtime When a previously generated cache is corrupted
  316.      * @throws Twig_Error_Syntax  When an error occurred during compilation
  317.      *
  318.      * @internal
  319.      */
  320.     public function loadTemplate($name$index null)
  321.     {
  322.         $cls $mainCls $this->getTemplateClass($name);
  323.         if (null !== $index) {
  324.             $cls .= '_'.$index;
  325.         }
  326.         if (isset($this->loadedTemplates[$cls])) {
  327.             return $this->loadedTemplates[$cls];
  328.         }
  329.         if (!class_exists($clsfalse)) {
  330.             $key $this->cache->generateKey($name$mainCls);
  331.             if (!$this->isAutoReload() || $this->isTemplateFresh($name$this->cache->getTimestamp($key))) {
  332.                 $this->cache->load($key);
  333.             }
  334.             if (!class_exists($clsfalse)) {
  335.                 $source $this->getLoader()->getSourceContext($name);
  336.                 $content $this->compileSource($source);
  337.                 $this->cache->write($key$content);
  338.                 $this->cache->load($key);
  339.                 if (!class_exists($mainClsfalse)) {
  340.                     /* Last line of defense if either $this->bcWriteCacheFile was used,
  341.                      * $this->cache is implemented as a no-op or we have a race condition
  342.                      * where the cache was cleared between the above calls to write to and load from
  343.                      * the cache.
  344.                      */
  345.                     eval('?>'.$content);
  346.                 }
  347.                 if (!class_exists($clsfalse)) {
  348.                     throw new Twig_Error_Runtime(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.'$name$index), -1$source);
  349.                 }
  350.             }
  351.         }
  352.         // to be removed in 3.0
  353.         $this->extensionSet->initRuntime($this);
  354.         if (isset($this->loading[$cls])) {
  355.             throw new Twig_Error_Runtime(sprintf('Circular reference detected for Twig template "%s", path: %s.'$nameimplode(' -> 'array_merge($this->loading, array($name)))));
  356.         }
  357.         $this->loading[$cls] = $name;
  358.         try {
  359.             $this->loadedTemplates[$cls] = new $cls($this);
  360.         } finally {
  361.             unset($this->loading[$cls]);
  362.         }
  363.         return $this->loadedTemplates[$cls];
  364.     }
  365.     /**
  366.      * Creates a template from source.
  367.      *
  368.      * This method should not be used as a generic way to load templates.
  369.      *
  370.      * @param string $template The template name
  371.      *
  372.      * @return Twig_Template A template instance representing the given template name
  373.      *
  374.      * @throws Twig_Error_Loader When the template cannot be found
  375.      * @throws Twig_Error_Syntax When an error occurred during compilation
  376.      */
  377.     public function createTemplate($template)
  378.     {
  379.         $name sprintf('__string_template__%s'hash('sha256'$templatefalse));
  380.         $loader = new Twig_Loader_Chain(array(
  381.             new Twig_Loader_Array(array($name => $template)),
  382.             $current $this->getLoader(),
  383.         ));
  384.         $this->setLoader($loader);
  385.         try {
  386.             $template $this->loadTemplate($name);
  387.         } finally {
  388.             $this->setLoader($current);
  389.         }
  390.         return $template;
  391.     }
  392.     /**
  393.      * Returns true if the template is still fresh.
  394.      *
  395.      * Besides checking the loader for freshness information,
  396.      * this method also checks if the enabled extensions have
  397.      * not changed.
  398.      *
  399.      * @param string $name The template name
  400.      * @param int    $time The last modification time of the cached template
  401.      *
  402.      * @return bool true if the template is fresh, false otherwise
  403.      */
  404.     public function isTemplateFresh($name$time)
  405.     {
  406.         return $this->extensionSet->getLastModified() <= $time && $this->getLoader()->isFresh($name$time);
  407.     }
  408.     /**
  409.      * Tries to load a template consecutively from an array.
  410.      *
  411.      * Similar to loadTemplate() but it also accepts instances of Twig_Template and
  412.      * Twig_TemplateWrapper, and an array of templates where each is tried to be loaded.
  413.      *
  414.      * @param string|Twig_Template|Twig_TemplateWrapper|array $names A template or an array of templates to try consecutively
  415.      *
  416.      * @return Twig_Template|Twig_TemplateWrapper
  417.      *
  418.      * @throws Twig_Error_Loader When none of the templates can be found
  419.      * @throws Twig_Error_Syntax When an error occurred during compilation
  420.      */
  421.     public function resolveTemplate($names)
  422.     {
  423.         if (!is_array($names)) {
  424.             $names = array($names);
  425.         }
  426.         foreach ($names as $name) {
  427.             if ($name instanceof Twig_Template) {
  428.                 return $name;
  429.             }
  430.             if ($name instanceof Twig_TemplateWrapper) {
  431.                 return $name;
  432.             }
  433.             try {
  434.                 return $this->loadTemplate($name);
  435.             } catch (Twig_Error_Loader $e) {
  436.             }
  437.         }
  438.         if (=== count($names)) {
  439.             throw $e;
  440.         }
  441.         throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".'implode('", "'$names)));
  442.     }
  443.     public function setLexer(Twig_Lexer $lexer)
  444.     {
  445.         $this->lexer $lexer;
  446.     }
  447.     /**
  448.      * Tokenizes a source code.
  449.      *
  450.      * @return Twig_TokenStream
  451.      *
  452.      * @throws Twig_Error_Syntax When the code is syntactically wrong
  453.      */
  454.     public function tokenize(Twig_Source $source)
  455.     {
  456.         if (null === $this->lexer) {
  457.             $this->lexer = new Twig_Lexer($this);
  458.         }
  459.         return $this->lexer->tokenize($source);
  460.     }
  461.     public function setParser(Twig_Parser $parser)
  462.     {
  463.         $this->parser $parser;
  464.     }
  465.     /**
  466.      * Converts a token stream to a node tree.
  467.      *
  468.      * @return Twig_Node_Module
  469.      *
  470.      * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
  471.      */
  472.     public function parse(Twig_TokenStream $stream)
  473.     {
  474.         if (null === $this->parser) {
  475.             $this->parser = new Twig_Parser($this);
  476.         }
  477.         return $this->parser->parse($stream);
  478.     }
  479.     public function setCompiler(Twig_Compiler $compiler)
  480.     {
  481.         $this->compiler $compiler;
  482.     }
  483.     /**
  484.      * Compiles a node and returns the PHP code.
  485.      *
  486.      * @return string The compiled PHP source code
  487.      */
  488.     public function compile(Twig_Node $node)
  489.     {
  490.         if (null === $this->compiler) {
  491.             $this->compiler = new Twig_Compiler($this);
  492.         }
  493.         return $this->compiler->compile($node)->getSource();
  494.     }
  495.     /**
  496.      * Compiles a template source code.
  497.      *
  498.      * @return string The compiled PHP source code
  499.      *
  500.      * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling
  501.      */
  502.     public function compileSource(Twig_Source $source)
  503.     {
  504.         try {
  505.             return $this->compile($this->parse($this->tokenize($source)));
  506.         } catch (Twig_Error $e) {
  507.             $e->setSourceContext($source);
  508.             throw $e;
  509.         } catch (Exception $e) {
  510.             throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").'$e->getMessage()), -1$source$e);
  511.         }
  512.     }
  513.     public function setLoader(Twig_LoaderInterface $loader)
  514.     {
  515.         $this->loader $loader;
  516.     }
  517.     /**
  518.      * Gets the Loader instance.
  519.      *
  520.      * @return Twig_LoaderInterface
  521.      */
  522.     public function getLoader()
  523.     {
  524.         return $this->loader;
  525.     }
  526.     /**
  527.      * Sets the default template charset.
  528.      *
  529.      * @param string $charset The default charset
  530.      */
  531.     public function setCharset($charset)
  532.     {
  533.         if ('UTF8' === $charset strtoupper($charset)) {
  534.             // iconv on Windows requires "UTF-8" instead of "UTF8"
  535.             $charset 'UTF-8';
  536.         }
  537.         $this->charset $charset;
  538.     }
  539.     /**
  540.      * Gets the default template charset.
  541.      *
  542.      * @return string The default charset
  543.      */
  544.     public function getCharset()
  545.     {
  546.         return $this->charset;
  547.     }
  548.     /**
  549.      * Returns true if the given extension is registered.
  550.      *
  551.      * @param string $class The extension class name
  552.      *
  553.      * @return bool Whether the extension is registered or not
  554.      */
  555.     public function hasExtension($class)
  556.     {
  557.         return $this->extensionSet->hasExtension($class);
  558.     }
  559.     /**
  560.      * Adds a runtime loader.
  561.      */
  562.     public function addRuntimeLoader(Twig_RuntimeLoaderInterface $loader)
  563.     {
  564.         $this->runtimeLoaders[] = $loader;
  565.     }
  566.     /**
  567.      * Gets an extension by class name.
  568.      *
  569.      * @param string $class The extension class name
  570.      *
  571.      * @return Twig_ExtensionInterface
  572.      */
  573.     public function getExtension($class)
  574.     {
  575.         return $this->extensionSet->getExtension($class);
  576.     }
  577.     /**
  578.      * Returns the runtime implementation of a Twig element (filter/function/test).
  579.      *
  580.      * @param string $class A runtime class name
  581.      *
  582.      * @return object The runtime implementation
  583.      *
  584.      * @throws Twig_Error_Runtime When the template cannot be found
  585.      */
  586.     public function getRuntime($class)
  587.     {
  588.         if (isset($this->runtimes[$class])) {
  589.             return $this->runtimes[$class];
  590.         }
  591.         foreach ($this->runtimeLoaders as $loader) {
  592.             if (null !== $runtime $loader->load($class)) {
  593.                 return $this->runtimes[$class] = $runtime;
  594.             }
  595.         }
  596.         throw new Twig_Error_Runtime(sprintf('Unable to load the "%s" runtime.'$class));
  597.     }
  598.     public function addExtension(Twig_ExtensionInterface $extension)
  599.     {
  600.         $this->extensionSet->addExtension($extension);
  601.         $this->updateOptionsHash();
  602.     }
  603.     /**
  604.      * Registers an array of extensions.
  605.      *
  606.      * @param array $extensions An array of extensions
  607.      */
  608.     public function setExtensions(array $extensions)
  609.     {
  610.         $this->extensionSet->setExtensions($extensions);
  611.         $this->updateOptionsHash();
  612.     }
  613.     /**
  614.      * Returns all registered extensions.
  615.      *
  616.      * @return Twig_ExtensionInterface[] An array of extensions (keys are for internal usage only and should not be relied on)
  617.      */
  618.     public function getExtensions()
  619.     {
  620.         return $this->extensionSet->getExtensions();
  621.     }
  622.     public function addTokenParser(Twig_TokenParserInterface $parser)
  623.     {
  624.         $this->extensionSet->addTokenParser($parser);
  625.     }
  626.     /**
  627.      * Gets the registered Token Parsers.
  628.      *
  629.      * @return Twig_TokenParserInterface[]
  630.      *
  631.      * @internal
  632.      */
  633.     public function getTokenParsers()
  634.     {
  635.         return $this->extensionSet->getTokenParsers();
  636.     }
  637.     /**
  638.      * Gets registered tags.
  639.      *
  640.      * @return Twig_TokenParserInterface[]
  641.      *
  642.      * @internal
  643.      */
  644.     public function getTags()
  645.     {
  646.         $tags = array();
  647.         foreach ($this->getTokenParsers() as $parser) {
  648.             $tags[$parser->getTag()] = $parser;
  649.         }
  650.         return $tags;
  651.     }
  652.     public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
  653.     {
  654.         $this->extensionSet->addNodeVisitor($visitor);
  655.     }
  656.     /**
  657.      * Gets the registered Node Visitors.
  658.      *
  659.      * @return Twig_NodeVisitorInterface[]
  660.      *
  661.      * @internal
  662.      */
  663.     public function getNodeVisitors()
  664.     {
  665.         return $this->extensionSet->getNodeVisitors();
  666.     }
  667.     public function addFilter(Twig_Filter $filter)
  668.     {
  669.         $this->extensionSet->addFilter($filter);
  670.     }
  671.     /**
  672.      * Get a filter by name.
  673.      *
  674.      * Subclasses may override this method and load filters differently;
  675.      * so no list of filters is available.
  676.      *
  677.      * @param string $name The filter name
  678.      *
  679.      * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
  680.      *
  681.      * @internal
  682.      */
  683.     public function getFilter($name)
  684.     {
  685.         return $this->extensionSet->getFilter($name);
  686.     }
  687.     public function registerUndefinedFilterCallback(callable $callable)
  688.     {
  689.         $this->extensionSet->registerUndefinedFilterCallback($callable);
  690.     }
  691.     /**
  692.      * Gets the registered Filters.
  693.      *
  694.      * Be warned that this method cannot return filters defined with registerUndefinedFilterCallback.
  695.      *
  696.      * @return Twig_Filter[]
  697.      *
  698.      * @see registerUndefinedFilterCallback
  699.      *
  700.      * @internal
  701.      */
  702.     public function getFilters()
  703.     {
  704.         return $this->extensionSet->getFilters();
  705.     }
  706.     /**
  707.      * Registers a Test.
  708.      *
  709.      * @param Twig_Test $test A Twig_Test instance
  710.      */
  711.     public function addTest(Twig_Test $test)
  712.     {
  713.         $this->extensionSet->addTest($test);
  714.     }
  715.     /**
  716.      * Gets the registered Tests.
  717.      *
  718.      * @return Twig_Test[]
  719.      *
  720.      * @internal
  721.      */
  722.     public function getTests()
  723.     {
  724.         return $this->extensionSet->getTests();
  725.     }
  726.     /**
  727.      * Gets a test by name.
  728.      *
  729.      * @param string $name The test name
  730.      *
  731.      * @return Twig_Test|false A Twig_Test instance or false if the test does not exist
  732.      *
  733.      * @internal
  734.      */
  735.     public function getTest($name)
  736.     {
  737.         return $this->extensionSet->getTest($name);
  738.     }
  739.     public function addFunction(Twig_Function $function)
  740.     {
  741.         $this->extensionSet->addFunction($function);
  742.     }
  743.     /**
  744.      * Get a function by name.
  745.      *
  746.      * Subclasses may override this method and load functions differently;
  747.      * so no list of functions is available.
  748.      *
  749.      * @param string $name function name
  750.      *
  751.      * @return Twig_Function|false A Twig_Function instance or false if the function does not exist
  752.      *
  753.      * @internal
  754.      */
  755.     public function getFunction($name)
  756.     {
  757.         return $this->extensionSet->getFunction($name);
  758.     }
  759.     public function registerUndefinedFunctionCallback(callable $callable)
  760.     {
  761.         $this->extensionSet->registerUndefinedFunctionCallback($callable);
  762.     }
  763.     /**
  764.      * Gets registered functions.
  765.      *
  766.      * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
  767.      *
  768.      * @return Twig_Function[]
  769.      *
  770.      * @see registerUndefinedFunctionCallback
  771.      *
  772.      * @internal
  773.      */
  774.     public function getFunctions()
  775.     {
  776.         return $this->extensionSet->getFunctions();
  777.     }
  778.     /**
  779.      * Registers a Global.
  780.      *
  781.      * New globals can be added before compiling or rendering a template;
  782.      * but after, you can only update existing globals.
  783.      *
  784.      * @param string $name  The global name
  785.      * @param mixed  $value The global value
  786.      */
  787.     public function addGlobal($name$value)
  788.     {
  789.         if ($this->extensionSet->isInitialized() && !array_key_exists($name$this->getGlobals())) {
  790.             throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.'$name));
  791.         }
  792.         if (null !== $this->resolvedGlobals) {
  793.             $this->resolvedGlobals[$name] = $value;
  794.         } else {
  795.             $this->globals[$name] = $value;
  796.         }
  797.     }
  798.     /**
  799.      * Gets the registered Globals.
  800.      *
  801.      * @return array An array of globals
  802.      *
  803.      * @internal
  804.      */
  805.     public function getGlobals()
  806.     {
  807.         if ($this->extensionSet->isInitialized()) {
  808.             if (null === $this->resolvedGlobals) {
  809.                 $this->resolvedGlobals array_merge($this->extensionSet->getGlobals(), $this->globals);
  810.             }
  811.             return $this->resolvedGlobals;
  812.         }
  813.         return array_merge($this->extensionSet->getGlobals(), $this->globals);
  814.     }
  815.     /**
  816.      * Merges a context with the defined globals.
  817.      *
  818.      * @param array $context An array representing the context
  819.      *
  820.      * @return array The context merged with the globals
  821.      */
  822.     public function mergeGlobals(array $context)
  823.     {
  824.         // we don't use array_merge as the context being generally
  825.         // bigger than globals, this code is faster.
  826.         foreach ($this->getGlobals() as $key => $value) {
  827.             if (!array_key_exists($key$context)) {
  828.                 $context[$key] = $value;
  829.             }
  830.         }
  831.         return $context;
  832.     }
  833.     /**
  834.      * Gets the registered unary Operators.
  835.      *
  836.      * @return array An array of unary operators
  837.      *
  838.      * @internal
  839.      */
  840.     public function getUnaryOperators()
  841.     {
  842.         return $this->extensionSet->getUnaryOperators();
  843.     }
  844.     /**
  845.      * Gets the registered binary Operators.
  846.      *
  847.      * @return array An array of binary operators
  848.      *
  849.      * @internal
  850.      */
  851.     public function getBinaryOperators()
  852.     {
  853.         return $this->extensionSet->getBinaryOperators();
  854.     }
  855.     private function updateOptionsHash()
  856.     {
  857.         $this->optionsHash implode(':', array(
  858.             $this->extensionSet->getSignature(),
  859.             PHP_MAJOR_VERSION,
  860.             PHP_MINOR_VERSION,
  861.             self::VERSION,
  862.             (int) $this->debug,
  863.             $this->baseTemplateClass,
  864.             (int) $this->strictVariables,
  865.         ));
  866.     }
  867. }
  868. class_alias('Twig_Environment''Twig\Environment'false);