Twig_Environment

Stores the Twig configuration.

Defined (1)

The class is defined in the following location(s).

/vendor/twig/twig/lib/Twig/Environment.php  
  1. class Twig_Environment 
  2. const VERSION = '1.32.1'; 
  3. const VERSION_ID = 13201; 
  4. const MAJOR_VERSION = 1; 
  5. const MINOR_VERSION = 32; 
  6. const RELEASE_VERSION = 1; 
  7. const EXTRA_VERSION = 'DEV'; 
  8.  
  9. protected $charset; 
  10. protected $loader; 
  11. protected $debug; 
  12. protected $autoReload; 
  13. protected $cache; 
  14. protected $lexer; 
  15. protected $parser; 
  16. protected $compiler; 
  17. protected $baseTemplateClass; 
  18. protected $extensions; 
  19. protected $parsers; 
  20. protected $visitors; 
  21. protected $filters; 
  22. protected $tests; 
  23. protected $functions; 
  24. protected $globals; 
  25. protected $runtimeInitialized = false; 
  26. protected $extensionInitialized = false; 
  27. protected $loadedTemplates; 
  28. protected $strictVariables; 
  29. protected $unaryOperators; 
  30. protected $binaryOperators; 
  31. protected $templateClassPrefix = '__TwigTemplate_'; 
  32. protected $functionCallbacks = array(); 
  33. protected $filterCallbacks = array(); 
  34. protected $staging; 
  35.  
  36. private $originalCache; 
  37. private $bcWriteCacheFile = false; 
  38. private $bcGetCacheFilename = false; 
  39. private $lastModifiedExtension = 0; 
  40. private $extensionsByClass = array(); 
  41. private $runtimeLoaders = array(); 
  42. private $runtimes = array(); 
  43. private $optionsHash; 
  44.  
  45. /** 
  46. * Constructor. 
  47. * Available options: 
  48. * * debug: When set to true, it automatically set "auto_reload" to true as 
  49. * well (default to false). 
  50. * * charset: The charset used by the templates (default to UTF-8). 
  51. * * base_template_class: The base template class to use for generated 
  52. * templates (default to Twig_Template). 
  53. * * cache: An absolute path where to store the compiled templates,  
  54. * a Twig_Cache_Interface implementation,  
  55. * or false to disable compilation cache (default). 
  56. * * auto_reload: Whether to reload the template if the original source changed. 
  57. * If you don't provide the auto_reload option, it will be 
  58. * determined automatically based on the debug value. 
  59. * * strict_variables: Whether to ignore invalid variables in templates 
  60. * (default to false). 
  61. * * autoescape: Whether to enable auto-escaping (default to html): 
  62. * * false: disable auto-escaping 
  63. * * true: equivalent to html 
  64. * * html, js: set the autoescaping to one of the supported strategies 
  65. * * name: set the autoescaping strategy based on the template name extension 
  66. * * PHP callback: a PHP callback that returns an escaping strategy based on the template "name" 
  67. * * optimizations: A flag that indicates which optimizations to apply 
  68. * (default to -1 which means that all optimizations are enabled; 
  69. * set it to 0 to disable). 
  70. * @param Twig_LoaderInterface $loader 
  71. * @param array $options An array of options 
  72. */ 
  73. public function __construct(Twig_LoaderInterface $loader = null, $options = array()) 
  74. if (null !== $loader) { 
  75. $this->setLoader($loader); 
  76. } else { 
  77. @trigger_error('Not passing a Twig_LoaderInterface as the first constructor argument of Twig_Environment is deprecated since version 1.21.', E_USER_DEPRECATED); 
  78.  
  79. $options = array_merge(array( 
  80. 'debug' => false,  
  81. 'charset' => 'UTF-8',  
  82. 'base_template_class' => 'Twig_Template',  
  83. 'strict_variables' => false,  
  84. 'autoescape' => 'html',  
  85. 'cache' => false,  
  86. 'auto_reload' => null,  
  87. 'optimizations' => -1,  
  88. ), $options); 
  89.  
  90. $this->debug = (bool) $options['debug']; 
  91. $this->charset = strtoupper($options['charset']); 
  92. $this->baseTemplateClass = $options['base_template_class']; 
  93. $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload']; 
  94. $this->strictVariables = (bool) $options['strict_variables']; 
  95. $this->setCache($options['cache']); 
  96.  
  97. $this->addExtension(new Twig_Extension_Core()); 
  98. $this->addExtension(new Twig_Extension_Escaper($options['autoescape'])); 
  99. $this->addExtension(new Twig_Extension_Optimizer($options['optimizations'])); 
  100. $this->staging = new Twig_Extension_Staging(); 
  101.  
  102. // For BC 
  103. if (is_string($this->originalCache)) { 
  104. $r = new ReflectionMethod($this, 'writeCacheFile'); 
  105. if ($r->getDeclaringClass()->getName() !== __CLASS__) { 
  106. @trigger_error('The Twig_Environment::writeCacheFile method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED); 
  107.  
  108. $this->bcWriteCacheFile = true; 
  109.  
  110. $r = new ReflectionMethod($this, 'getCacheFilename'); 
  111. if ($r->getDeclaringClass()->getName() !== __CLASS__) { 
  112. @trigger_error('The Twig_Environment::getCacheFilename method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED); 
  113.  
  114. $this->bcGetCacheFilename = true; 
  115.  
  116. /** 
  117. * Gets the base template class for compiled templates. 
  118. * @return string The base template class name 
  119. */ 
  120. public function getBaseTemplateClass() 
  121. return $this->baseTemplateClass; 
  122.  
  123. /** 
  124. * Sets the base template class for compiled templates. 
  125. * @param string $class The base template class name 
  126. */ 
  127. public function setBaseTemplateClass($class) 
  128. $this->baseTemplateClass = $class; 
  129. $this->updateOptionsHash(); 
  130.  
  131. /** 
  132. * Enables debugging mode. 
  133. */ 
  134. public function enableDebug() 
  135. $this->debug = true; 
  136. $this->updateOptionsHash(); 
  137.  
  138. /** 
  139. * Disables debugging mode. 
  140. */ 
  141. public function disableDebug() 
  142. $this->debug = false; 
  143. $this->updateOptionsHash(); 
  144.  
  145. /** 
  146. * Checks if debug mode is enabled. 
  147. * @return bool true if debug mode is enabled, false otherwise 
  148. */ 
  149. public function isDebug() 
  150. return $this->debug; 
  151.  
  152. /** 
  153. * Enables the auto_reload option. 
  154. */ 
  155. public function enableAutoReload() 
  156. $this->autoReload = true; 
  157.  
  158. /** 
  159. * Disables the auto_reload option. 
  160. */ 
  161. public function disableAutoReload() 
  162. $this->autoReload = false; 
  163.  
  164. /** 
  165. * Checks if the auto_reload option is enabled. 
  166. * @return bool true if auto_reload is enabled, false otherwise 
  167. */ 
  168. public function isAutoReload() 
  169. return $this->autoReload; 
  170.  
  171. /** 
  172. * Enables the strict_variables option. 
  173. */ 
  174. public function enableStrictVariables() 
  175. $this->strictVariables = true; 
  176. $this->updateOptionsHash(); 
  177.  
  178. /** 
  179. * Disables the strict_variables option. 
  180. */ 
  181. public function disableStrictVariables() 
  182. $this->strictVariables = false; 
  183. $this->updateOptionsHash(); 
  184.  
  185. /** 
  186. * Checks if the strict_variables option is enabled. 
  187. * @return bool true if strict_variables is enabled, false otherwise 
  188. */ 
  189. public function isStrictVariables() 
  190. return $this->strictVariables; 
  191.  
  192. /** 
  193. * Gets the current cache implementation. 
  194. * @param bool $original Whether to return the original cache option or the real cache instance 
  195. * @return Twig_CacheInterface|string|false A Twig_CacheInterface implementation,  
  196. * an absolute path to the compiled templates,  
  197. * or false to disable cache 
  198. */ 
  199. public function getCache($original = true) 
  200. return $original ? $this->originalCache : $this->cache; 
  201.  
  202. /** 
  203. * Sets the current cache implementation. 
  204. * @param Twig_CacheInterface|string|false $cache A Twig_CacheInterface implementation,  
  205. * an absolute path to the compiled templates,  
  206. * or false to disable cache 
  207. */ 
  208. public function setCache($cache) 
  209. if (is_string($cache)) { 
  210. $this->originalCache = $cache; 
  211. $this->cache = new Twig_Cache_Filesystem($cache); 
  212. } elseif (false === $cache) { 
  213. $this->originalCache = $cache; 
  214. $this->cache = new Twig_Cache_Null(); 
  215. } elseif (null === $cache) { 
  216. @trigger_error('Using "null" as the cache strategy is deprecated since version 1.23 and will be removed in Twig 2.0.', E_USER_DEPRECATED); 
  217. $this->originalCache = false; 
  218. $this->cache = new Twig_Cache_Null(); 
  219. } elseif ($cache instanceof Twig_CacheInterface) { 
  220. $this->originalCache = $this->cache = $cache; 
  221. } else { 
  222. throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.')); 
  223.  
  224. /** 
  225. * Gets the cache filename for a given template. 
  226. * @param string $name The template name 
  227. * @return string|false The cache file name or false when caching is disabled 
  228. * @deprecated since 1.22 (to be removed in 2.0) 
  229. */ 
  230. public function getCacheFilename($name) 
  231. @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 
  232.  
  233. $key = $this->cache->generateKey($name, $this->getTemplateClass($name)); 
  234.  
  235. return !$key ? false : $key; 
  236.  
  237. /** 
  238. * Gets the template class associated with the given string. 
  239. * The generated template class is based on the following parameters: 
  240. * * The cache key for the given template; 
  241. * * The currently enabled extensions; 
  242. * * Whether the Twig C extension is available or not; 
  243. * * PHP version; 
  244. * * Twig version; 
  245. * * Options with what environment was created. 
  246. * @param string $name The name for which to calculate the template class name 
  247. * @param int|null $index The index if it is an embedded template 
  248. * @return string The template class name 
  249. */ 
  250. public function getTemplateClass($name, $index = null) 
  251. $key = $this->getLoader()->getCacheKey($name).$this->optionsHash; 
  252.  
  253. return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '_'.$index); 
  254.  
  255. /** 
  256. * Gets the template class prefix. 
  257. * @return string The template class prefix 
  258. * @deprecated since 1.22 (to be removed in 2.0) 
  259. */ 
  260. public function getTemplateClassPrefix() 
  261. @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 
  262.  
  263. return $this->templateClassPrefix; 
  264.  
  265. /** 
  266. * Renders a template. 
  267. * @param string $name The template name 
  268. * @param array $context An array of parameters to pass to the template 
  269. * @return string The rendered template 
  270. * @throws Twig_Error_Loader When the template cannot be found 
  271. * @throws Twig_Error_Syntax When an error occurred during compilation 
  272. * @throws Twig_Error_Runtime When an error occurred during rendering 
  273. */ 
  274. public function render($name, array $context = array()) 
  275. return $this->loadTemplate($name)->render($context); 
  276.  
  277. /** 
  278. * Displays a template. 
  279. * @param string $name The template name 
  280. * @param array $context An array of parameters to pass to the template 
  281. * @throws Twig_Error_Loader When the template cannot be found 
  282. * @throws Twig_Error_Syntax When an error occurred during compilation 
  283. * @throws Twig_Error_Runtime When an error occurred during rendering 
  284. */ 
  285. public function display($name, array $context = array()) 
  286. $this->loadTemplate($name)->display($context); 
  287.  
  288. /** 
  289. * Loads a template. 
  290. * @param string|Twig_TemplateWrapper|Twig_Template $name The template name 
  291. * @return Twig_TemplateWrapper 
  292. */ 
  293. public function load($name) 
  294. if ($name instanceof Twig_TemplateWrapper) { 
  295. return $name; 
  296.  
  297. if ($name instanceof Twig_Template) { 
  298. return new Twig_TemplateWrapper($this, $name); 
  299.  
  300. return new Twig_TemplateWrapper($this, $this->loadTemplate($name)); 
  301.  
  302. /** 
  303. * Loads a template internal representation. 
  304. * This method is for internal use only and should never be called 
  305. * directly. 
  306. * @param string $name The template name 
  307. * @param int $index The index if it is an embedded template 
  308. * @return Twig_TemplateInterface A template instance representing the given template name 
  309. * @throws Twig_Error_Loader When the template cannot be found 
  310. * @throws Twig_Error_Runtime When a previously generated cache is corrupted 
  311. * @throws Twig_Error_Syntax When an error occurred during compilation 
  312. * @internal 
  313. */ 
  314. public function loadTemplate($name, $index = null) 
  315. $cls = $mainCls = $this->getTemplateClass($name); 
  316. if (null !== $index) { 
  317. $cls .= '_'.$index; 
  318.  
  319. if (isset($this->loadedTemplates[$cls])) { 
  320. return $this->loadedTemplates[$cls]; 
  321.  
  322. if (!class_exists($cls, false)) { 
  323. if ($this->bcGetCacheFilename) { 
  324. $key = $this->getCacheFilename($name); 
  325. } else { 
  326. $key = $this->cache->generateKey($name, $mainCls); 
  327.  
  328. if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) { 
  329. $this->cache->load($key); 
  330.  
  331. if (!class_exists($cls, false)) { 
  332. $loader = $this->getLoader(); 
  333. if (!$loader instanceof Twig_SourceContextLoaderInterface) { 
  334. $source = new Twig_Source($loader->getSource($name), $name); 
  335. } else { 
  336. $source = $loader->getSourceContext($name); 
  337.  
  338. $content = $this->compileSource($source); 
  339.  
  340. if ($this->bcWriteCacheFile) { 
  341. $this->writeCacheFile($key, $content); 
  342. } else { 
  343. $this->cache->write($key, $content); 
  344. $this->cache->load($key); 
  345.  
  346. if (!class_exists($mainCls, false)) { 
  347. /** Last line of defense if either $this->bcWriteCacheFile was used,  
  348. * $this->cache is implemented as a no-op or we have a race condition 
  349. * where the cache was cleared between the above calls to write to and load from 
  350. * the cache. 
  351. */ 
  352. eval('?>'.$content); 
  353.  
  354. if (!class_exists($cls, false)) { 
  355. throw new Twig_Error_Runtime(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.', $name, $index), -1, $source); 
  356.  
  357. if (!$this->runtimeInitialized) { 
  358. $this->initRuntime(); 
  359.  
  360. return $this->loadedTemplates[$cls] = new $cls($this); 
  361.  
  362. /** 
  363. * Creates a template from source. 
  364. * This method should not be used as a generic way to load templates. 
  365. * @param string $template The template name 
  366. * @return Twig_Template A template instance representing the given template name 
  367. * @throws Twig_Error_Loader When the template cannot be found 
  368. * @throws Twig_Error_Syntax When an error occurred during compilation 
  369. */ 
  370. public function createTemplate($template) 
  371. $name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false)); 
  372.  
  373. $loader = new Twig_Loader_Chain(array( 
  374. new Twig_Loader_Array(array($name => $template)),  
  375. $current = $this->getLoader(),  
  376. )); 
  377.  
  378. $this->setLoader($loader); 
  379. try { 
  380. $template = $this->loadTemplate($name); 
  381. } catch (Exception $e) { 
  382. $this->setLoader($current); 
  383.  
  384. throw $e; 
  385. } catch (Throwable $e) { 
  386. $this->setLoader($current); 
  387.  
  388. throw $e; 
  389. $this->setLoader($current); 
  390.  
  391. return $template; 
  392.  
  393. /** 
  394. * Returns true if the template is still fresh. 
  395. * Besides checking the loader for freshness information,  
  396. * this method also checks if the enabled extensions have 
  397. * not changed. 
  398. * @param string $name The template name 
  399. * @param int $time The last modification time of the cached template 
  400. * @return bool true if the template is fresh, false otherwise 
  401. */ 
  402. public function isTemplateFresh($name, $time) 
  403. if (0 === $this->lastModifiedExtension) { 
  404. foreach ($this->extensions as $extension) { 
  405. $r = new ReflectionObject($extension); 
  406. if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModifiedExtension) { 
  407. $this->lastModifiedExtension = $extensionTime; 
  408.  
  409. return $this->lastModifiedExtension <= $time && $this->getLoader()->isFresh($name, $time); 
  410.  
  411. /** 
  412. * Tries to load a template consecutively from an array. 
  413. * Similar to loadTemplate() but it also accepts Twig_TemplateInterface instances and an array 
  414. * of templates where each is tried to be loaded. 
  415. * @param string|Twig_Template|array $names A template or an array of templates to try consecutively 
  416. * @return Twig_Template 
  417. * @throws Twig_Error_Loader When none of the templates can be found 
  418. * @throws Twig_Error_Syntax When an error occurred during compilation 
  419. */ 
  420. public function resolveTemplate($names) 
  421. if (!is_array($names)) { 
  422. $names = array($names); 
  423.  
  424. foreach ($names as $name) { 
  425. if ($name instanceof Twig_Template) { 
  426. return $name; 
  427.  
  428. try { 
  429. return $this->loadTemplate($name); 
  430. } catch (Twig_Error_Loader $e) { 
  431.  
  432. if (1 === count($names)) { 
  433. throw $e; 
  434.  
  435. throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names))); 
  436.  
  437. /** 
  438. * Clears the internal template cache. 
  439. * @deprecated since 1.18.3 (to be removed in 2.0) 
  440. */ 
  441. public function clearTemplateCache() 
  442. @trigger_error(sprintf('The %s method is deprecated since version 1.18.3 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 
  443.  
  444. $this->loadedTemplates = array(); 
  445.  
  446. /** 
  447. * Clears the template cache files on the filesystem. 
  448. * @deprecated since 1.22 (to be removed in 2.0) 
  449. */ 
  450. public function clearCacheFiles() 
  451. @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 
  452.  
  453. if (is_string($this->originalCache)) { 
  454. foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->originalCache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { 
  455. if ($file->isFile()) { 
  456. @unlink($file->getPathname()); 
  457.  
  458. /** 
  459. * Gets the Lexer instance. 
  460. * @return Twig_LexerInterface 
  461. * @deprecated since 1.25 (to be removed in 2.0) 
  462. */ 
  463. public function getLexer() 
  464. @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); 
  465.  
  466. if (null === $this->lexer) { 
  467. $this->lexer = new Twig_Lexer($this); 
  468.  
  469. return $this->lexer; 
  470.  
  471. public function setLexer(Twig_LexerInterface $lexer) 
  472. $this->lexer = $lexer; 
  473.  
  474. /** 
  475. * Tokenizes a source code. 
  476. * @param string|Twig_Source $source The template source code 
  477. * @param string $name The template name (deprecated) 
  478. * @return Twig_TokenStream 
  479. * @throws Twig_Error_Syntax When the code is syntactically wrong 
  480. */ 
  481. public function tokenize($source, $name = null) 
  482. if (!$source instanceof Twig_Source) { 
  483. @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); 
  484. $source = new Twig_Source($source, $name); 
  485.  
  486. if (null === $this->lexer) { 
  487. $this->lexer = new Twig_Lexer($this); 
  488.  
  489. return $this->lexer->tokenize($source); 
  490.  
  491. /** 
  492. * Gets the Parser instance. 
  493. * @return Twig_ParserInterface 
  494. * @deprecated since 1.25 (to be removed in 2.0) 
  495. */ 
  496. public function getParser() 
  497. @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); 
  498.  
  499. if (null === $this->parser) { 
  500. $this->parser = new Twig_Parser($this); 
  501.  
  502. return $this->parser; 
  503.  
  504. public function setParser(Twig_ParserInterface $parser) 
  505. $this->parser = $parser; 
  506.  
  507. /** 
  508. * Converts a token stream to a node tree. 
  509. * @return Twig_Node_Module 
  510. * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong 
  511. */ 
  512. public function parse(Twig_TokenStream $stream) 
  513. if (null === $this->parser) { 
  514. $this->parser = new Twig_Parser($this); 
  515.  
  516. return $this->parser->parse($stream); 
  517.  
  518. /** 
  519. * Gets the Compiler instance. 
  520. * @return Twig_CompilerInterface 
  521. * @deprecated since 1.25 (to be removed in 2.0) 
  522. */ 
  523. public function getCompiler() 
  524. @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); 
  525.  
  526. if (null === $this->compiler) { 
  527. $this->compiler = new Twig_Compiler($this); 
  528.  
  529. return $this->compiler; 
  530.  
  531. public function setCompiler(Twig_CompilerInterface $compiler) 
  532. $this->compiler = $compiler; 
  533.  
  534. /** 
  535. * Compiles a node and returns the PHP code. 
  536. * @return string The compiled PHP source code 
  537. */ 
  538. public function compile(Twig_NodeInterface $node) 
  539. if (null === $this->compiler) { 
  540. $this->compiler = new Twig_Compiler($this); 
  541.  
  542. return $this->compiler->compile($node)->getSource(); 
  543.  
  544. /** 
  545. * Compiles a template source code. 
  546. * @param string|Twig_Source $source The template source code 
  547. * @param string $name The template name (deprecated) 
  548. * @return string The compiled PHP source code 
  549. * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling 
  550. */ 
  551. public function compileSource($source, $name = null) 
  552. if (!$source instanceof Twig_Source) { 
  553. @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); 
  554. $source = new Twig_Source($source, $name); 
  555.  
  556. try { 
  557. return $this->compile($this->parse($this->tokenize($source))); 
  558. } catch (Twig_Error $e) { 
  559. $e->setSourceContext($source); 
  560. throw $e; 
  561. } catch (Exception $e) { 
  562. throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e); 
  563.  
  564. public function setLoader(Twig_LoaderInterface $loader) 
  565. if (!$loader instanceof Twig_SourceContextLoaderInterface && 0 !== strpos(get_class($loader), 'Mock_Twig_LoaderInterface')) { 
  566. @trigger_error(sprintf('Twig loader "%s" should implement Twig_SourceContextLoaderInterface since version 1.27.', get_class($loader)), E_USER_DEPRECATED); 
  567.  
  568. $this->loader = $loader; 
  569.  
  570. /** 
  571. * Gets the Loader instance. 
  572. * @return Twig_LoaderInterface 
  573. */ 
  574. public function getLoader() 
  575. if (null === $this->loader) { 
  576. throw new LogicException('You must set a loader first.'); 
  577.  
  578. return $this->loader; 
  579.  
  580. /** 
  581. * Sets the default template charset. 
  582. * @param string $charset The default charset 
  583. */ 
  584. public function setCharset($charset) 
  585. $this->charset = strtoupper($charset); 
  586.  
  587. /** 
  588. * Gets the default template charset. 
  589. * @return string The default charset 
  590. */ 
  591. public function getCharset() 
  592. return $this->charset; 
  593.  
  594. /** 
  595. * Initializes the runtime environment. 
  596. * @deprecated since 1.23 (to be removed in 2.0) 
  597. */ 
  598. public function initRuntime() 
  599. $this->runtimeInitialized = true; 
  600.  
  601. foreach ($this->getExtensions() as $name => $extension) { 
  602. if (!$extension instanceof Twig_Extension_InitRuntimeInterface) { 
  603. $m = new ReflectionMethod($extension, 'initRuntime'); 
  604.  
  605. if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) { 
  606. @trigger_error(sprintf('Defining the initRuntime() method in the "%s" extension is deprecated since version 1.23. Use the `needs_environment` option to get the Twig_Environment instance in filters, functions, or tests; or explicitly implement Twig_Extension_InitRuntimeInterface if needed (not recommended).', $name), E_USER_DEPRECATED); 
  607.  
  608. $extension->initRuntime($this); 
  609.  
  610. /** 
  611. * Returns true if the given extension is registered. 
  612. * @param string $class The extension class name 
  613. * @return bool Whether the extension is registered or not 
  614. */ 
  615. public function hasExtension($class) 
  616. $class = ltrim($class, '\\'); 
  617. if (isset($this->extensions[$class])) { 
  618. if ($class !== get_class($this->extensions[$class])) { 
  619. @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); 
  620.  
  621. return true; 
  622.  
  623. return isset($this->extensionsByClass[$class]); 
  624.  
  625. /** 
  626. * Adds a runtime loader. 
  627. */ 
  628. public function addRuntimeLoader(Twig_RuntimeLoaderInterface $loader) 
  629. $this->runtimeLoaders[] = $loader; 
  630.  
  631. /** 
  632. * Gets an extension by class name. 
  633. * @param string $class The extension class name 
  634. * @return Twig_ExtensionInterface 
  635. */ 
  636. public function getExtension($class) 
  637. $class = ltrim($class, '\\'); 
  638.  
  639. if (isset($this->extensions[$class])) { 
  640. if ($class !== get_class($this->extensions[$class])) { 
  641. @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); 
  642.  
  643. return $this->extensions[$class]; 
  644.  
  645. if (!isset($this->extensionsByClass[$class])) { 
  646. throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $class)); 
  647.  
  648. return $this->extensionsByClass[$class]; 
  649.  
  650. /** 
  651. * Returns the runtime implementation of a Twig element (filter/function/test). 
  652. * @param string $class A runtime class name 
  653. * @return object The runtime implementation 
  654. * @throws Twig_Error_Runtime When the template cannot be found 
  655. */ 
  656. public function getRuntime($class) 
  657. if (isset($this->runtimes[$class])) { 
  658. return $this->runtimes[$class]; 
  659.  
  660. foreach ($this->runtimeLoaders as $loader) { 
  661. if (null !== $runtime = $loader->load($class)) { 
  662. return $this->runtimes[$class] = $runtime; 
  663.  
  664. throw new Twig_Error_Runtime(sprintf('Unable to load the "%s" runtime.', $class)); 
  665.  
  666. public function addExtension(Twig_ExtensionInterface $extension) 
  667. if ($this->extensionInitialized) { 
  668. throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName())); 
  669.  
  670. $class = get_class($extension); 
  671. if ($class !== $extension->getName()) { 
  672. if (isset($this->extensions[$extension->getName()])) { 
  673. unset($this->extensions[$extension->getName()], $this->extensionsByClass[$class]); 
  674. @trigger_error(sprintf('The possibility to register the same extension twice ("%s") is deprecated since version 1.23 and will be removed in Twig 2.0. Use proper PHP inheritance instead.', $extension->getName()), E_USER_DEPRECATED); 
  675.  
  676. $this->lastModifiedExtension = 0; 
  677. $this->extensionsByClass[$class] = $extension; 
  678. $this->extensions[$extension->getName()] = $extension; 
  679. $this->updateOptionsHash(); 
  680.  
  681. /** 
  682. * Removes an extension by name. 
  683. * This method is deprecated and you should not use it. 
  684. * @param string $name The extension name 
  685. * @deprecated since 1.12 (to be removed in 2.0) 
  686. */ 
  687. public function removeExtension($name) 
  688. @trigger_error(sprintf('The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 
  689.  
  690. if ($this->extensionInitialized) { 
  691. throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name)); 
  692.  
  693. $class = ltrim($name, '\\'); 
  694. if (isset($this->extensions[$class])) { 
  695. if ($class !== get_class($this->extensions[$class])) { 
  696. @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); 
  697.  
  698. unset($this->extensions[$class]); 
  699.  
  700. unset($this->extensions[$class]); 
  701. $this->updateOptionsHash(); 
  702.  
  703. /** 
  704. * Registers an array of extensions. 
  705. * @param array $extensions An array of extensions 
  706. */ 
  707. public function setExtensions(array $extensions) 
  708. foreach ($extensions as $extension) { 
  709. $this->addExtension($extension); 
  710.  
  711. /** 
  712. * Returns all registered extensions. 
  713. * @return Twig_ExtensionInterface[] An array of extensions (keys are for internal usage only and should not be relied on) 
  714. */ 
  715. public function getExtensions() 
  716. return $this->extensions; 
  717.  
  718. public function addTokenParser(Twig_TokenParserInterface $parser) 
  719. if ($this->extensionInitialized) { 
  720. throw new LogicException('Unable to add a token parser as extensions have already been initialized.'); 
  721.  
  722. $this->staging->addTokenParser($parser); 
  723.  
  724. /** 
  725. * Gets the registered Token Parsers. 
  726. * @return Twig_TokenParserBrokerInterface 
  727. * @internal 
  728. */ 
  729. public function getTokenParsers() 
  730. if (!$this->extensionInitialized) { 
  731. $this->initExtensions(); 
  732.  
  733. return $this->parsers; 
  734.  
  735. /** 
  736. * Gets registered tags. 
  737. * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes. 
  738. * @return Twig_TokenParserInterface[] 
  739. * @internal 
  740. */ 
  741. public function getTags() 
  742. $tags = array(); 
  743. foreach ($this->getTokenParsers()->getParsers() as $parser) { 
  744. if ($parser instanceof Twig_TokenParserInterface) { 
  745. $tags[$parser->getTag()] = $parser; 
  746.  
  747. return $tags; 
  748.  
  749. public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) 
  750. if ($this->extensionInitialized) { 
  751. throw new LogicException('Unable to add a node visitor as extensions have already been initialized.'); 
  752.  
  753. $this->staging->addNodeVisitor($visitor); 
  754.  
  755. /** 
  756. * Gets the registered Node Visitors. 
  757. * @return Twig_NodeVisitorInterface[] 
  758. * @internal 
  759. */ 
  760. public function getNodeVisitors() 
  761. if (!$this->extensionInitialized) { 
  762. $this->initExtensions(); 
  763.  
  764. return $this->visitors; 
  765.  
  766. /** 
  767. * Registers a Filter. 
  768. * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance 
  769. * @param Twig_FilterInterface|Twig_SimpleFilter $filter 
  770. */ 
  771. public function addFilter($name, $filter = null) 
  772. if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) { 
  773. throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter.'); 
  774.  
  775. if ($name instanceof Twig_SimpleFilter) { 
  776. $filter = $name; 
  777. $name = $filter->getName(); 
  778. } else { 
  779. @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFilter" instead when defining filter "%s".', __METHOD__, $name), E_USER_DEPRECATED); 
  780.  
  781. if ($this->extensionInitialized) { 
  782. throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name)); 
  783.  
  784. $this->staging->addFilter($name, $filter); 
  785.  
  786. /** 
  787. * Get a filter by name. 
  788. * Subclasses may override this method and load filters differently; 
  789. * so no list of filters is available. 
  790. * @param string $name The filter name 
  791. * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist 
  792. * @internal 
  793. */ 
  794. public function getFilter($name) 
  795. if (!$this->extensionInitialized) { 
  796. $this->initExtensions(); 
  797.  
  798. if (isset($this->filters[$name])) { 
  799. return $this->filters[$name]; 
  800.  
  801. foreach ($this->filters as $pattern => $filter) { 
  802. $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); 
  803.  
  804. if ($count) { 
  805. if (preg_match('#^'.$pattern.'$#', $name, $matches)) { 
  806. array_shift($matches); 
  807. $filter->setArguments($matches); 
  808.  
  809. return $filter; 
  810.  
  811. foreach ($this->filterCallbacks as $callback) { 
  812. if (false !== $filter = call_user_func($callback, $name)) { 
  813. return $filter; 
  814.  
  815. return false; 
  816.  
  817. public function registerUndefinedFilterCallback($callable) 
  818. $this->filterCallbacks[] = $callable; 
  819.  
  820. /** 
  821. * Gets the registered Filters. 
  822. * Be warned that this method cannot return filters defined with registerUndefinedFilterCallback. 
  823. * @return Twig_FilterInterface[] 
  824. * @see registerUndefinedFilterCallback 
  825. * @internal 
  826. */ 
  827. public function getFilters() 
  828. if (!$this->extensionInitialized) { 
  829. $this->initExtensions(); 
  830.  
  831. return $this->filters; 
  832.  
  833. /** 
  834. * Registers a Test. 
  835. * @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance 
  836. * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance 
  837. */ 
  838. public function addTest($name, $test = null) 
  839. if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) { 
  840. throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest.'); 
  841.  
  842. if ($name instanceof Twig_SimpleTest) { 
  843. $test = $name; 
  844. $name = $test->getName(); 
  845. } else { 
  846. @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleTest" instead when defining test "%s".', __METHOD__, $name), E_USER_DEPRECATED); 
  847.  
  848. if ($this->extensionInitialized) { 
  849. throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name)); 
  850.  
  851. $this->staging->addTest($name, $test); 
  852.  
  853. /** 
  854. * Gets the registered Tests. 
  855. * @return Twig_TestInterface[] 
  856. * @internal 
  857. */ 
  858. public function getTests() 
  859. if (!$this->extensionInitialized) { 
  860. $this->initExtensions(); 
  861.  
  862. return $this->tests; 
  863.  
  864. /** 
  865. * Gets a test by name. 
  866. * @param string $name The test name 
  867. * @return Twig_Test|false A Twig_Test instance or false if the test does not exist 
  868. * @internal 
  869. */ 
  870. public function getTest($name) 
  871. if (!$this->extensionInitialized) { 
  872. $this->initExtensions(); 
  873.  
  874. if (isset($this->tests[$name])) { 
  875. return $this->tests[$name]; 
  876.  
  877. return false; 
  878.  
  879. /** 
  880. * Registers a Function. 
  881. * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance 
  882. * @param Twig_FunctionInterface|Twig_SimpleFunction $function 
  883. */ 
  884. public function addFunction($name, $function = null) 
  885. if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) { 
  886. throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction.'); 
  887.  
  888. if ($name instanceof Twig_SimpleFunction) { 
  889. $function = $name; 
  890. $name = $function->getName(); 
  891. } else { 
  892. @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFunction" instead when defining function "%s".', __METHOD__, $name), E_USER_DEPRECATED); 
  893.  
  894. if ($this->extensionInitialized) { 
  895. throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name)); 
  896.  
  897. $this->staging->addFunction($name, $function); 
  898.  
  899. /** 
  900. * Get a function by name. 
  901. * Subclasses may override this method and load functions differently; 
  902. * so no list of functions is available. 
  903. * @param string $name function name 
  904. * @return Twig_Function|false A Twig_Function instance or false if the function does not exist 
  905. * @internal 
  906. */ 
  907. public function getFunction($name) 
  908. if (!$this->extensionInitialized) { 
  909. $this->initExtensions(); 
  910.  
  911. if (isset($this->functions[$name])) { 
  912. return $this->functions[$name]; 
  913.  
  914. foreach ($this->functions as $pattern => $function) { 
  915. $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); 
  916.  
  917. if ($count) { 
  918. if (preg_match('#^'.$pattern.'$#', $name, $matches)) { 
  919. array_shift($matches); 
  920. $function->setArguments($matches); 
  921.  
  922. return $function; 
  923.  
  924. foreach ($this->functionCallbacks as $callback) { 
  925. if (false !== $function = call_user_func($callback, $name)) { 
  926. return $function; 
  927.  
  928. return false; 
  929.  
  930. public function registerUndefinedFunctionCallback($callable) 
  931. $this->functionCallbacks[] = $callable; 
  932.  
  933. /** 
  934. * Gets registered functions. 
  935. * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback. 
  936. * @return Twig_FunctionInterface[] 
  937. * @see registerUndefinedFunctionCallback 
  938. * @internal 
  939. */ 
  940. public function getFunctions() 
  941. if (!$this->extensionInitialized) { 
  942. $this->initExtensions(); 
  943.  
  944. return $this->functions; 
  945.  
  946. /** 
  947. * Registers a Global. 
  948. * New globals can be added before compiling or rendering a template; 
  949. * but after, you can only update existing globals. 
  950. * @param string $name The global name 
  951. * @param mixed $value The global value 
  952. */ 
  953. public function addGlobal($name, $value) 
  954. if ($this->extensionInitialized || $this->runtimeInitialized) { 
  955. if (null === $this->globals) { 
  956. $this->globals = $this->initGlobals(); 
  957.  
  958. if (!array_key_exists($name, $this->globals)) { 
  959. // The deprecation notice must be turned into the following exception in Twig 2.0 
  960. @trigger_error(sprintf('Registering global variable "%s" at runtime or when the extensions have already been initialized is deprecated since version 1.21.', $name), E_USER_DEPRECATED); 
  961. //throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); 
  962.  
  963. if ($this->extensionInitialized || $this->runtimeInitialized) { 
  964. // update the value 
  965. $this->globals[$name] = $value; 
  966. } else { 
  967. $this->staging->addGlobal($name, $value); 
  968.  
  969. /** 
  970. * Gets the registered Globals. 
  971. * @return array An array of globals 
  972. * @internal 
  973. */ 
  974. public function getGlobals() 
  975. if (!$this->runtimeInitialized && !$this->extensionInitialized) { 
  976. return $this->initGlobals(); 
  977.  
  978. if (null === $this->globals) { 
  979. $this->globals = $this->initGlobals(); 
  980.  
  981. return $this->globals; 
  982.  
  983. /** 
  984. * Merges a context with the defined globals. 
  985. * @param array $context An array representing the context 
  986. * @return array The context merged with the globals 
  987. */ 
  988. public function mergeGlobals(array $context) 
  989. // we don't use array_merge as the context being generally 
  990. // bigger than globals, this code is faster. 
  991. foreach ($this->getGlobals() as $key => $value) { 
  992. if (!array_key_exists($key, $context)) { 
  993. $context[$key] = $value; 
  994.  
  995. return $context; 
  996.  
  997. /** 
  998. * Gets the registered unary Operators. 
  999. * @return array An array of unary operators 
  1000. * @internal 
  1001. */ 
  1002. public function getUnaryOperators() 
  1003. if (!$this->extensionInitialized) { 
  1004. $this->initExtensions(); 
  1005.  
  1006. return $this->unaryOperators; 
  1007.  
  1008. /** 
  1009. * Gets the registered binary Operators. 
  1010. * @return array An array of binary operators 
  1011. * @internal 
  1012. */ 
  1013. public function getBinaryOperators() 
  1014. if (!$this->extensionInitialized) { 
  1015. $this->initExtensions(); 
  1016.  
  1017. return $this->binaryOperators; 
  1018.  
  1019. /** 
  1020. * @deprecated since 1.23 (to be removed in 2.0) 
  1021. */ 
  1022. public function computeAlternatives($name, $items) 
  1023. @trigger_error(sprintf('The %s method is deprecated since version 1.23 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 
  1024.  
  1025. return Twig_Error_Syntax::computeAlternatives($name, $items); 
  1026.  
  1027. /** 
  1028. * @internal 
  1029. */ 
  1030. protected function initGlobals() 
  1031. $globals = array(); 
  1032. foreach ($this->extensions as $name => $extension) { 
  1033. if (!$extension instanceof Twig_Extension_GlobalsInterface) { 
  1034. $m = new ReflectionMethod($extension, 'getGlobals'); 
  1035.  
  1036. if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) { 
  1037. @trigger_error(sprintf('Defining the getGlobals() method in the "%s" extension without explicitly implementing Twig_Extension_GlobalsInterface is deprecated since version 1.23.', $name), E_USER_DEPRECATED); 
  1038.  
  1039. $extGlob = $extension->getGlobals(); 
  1040. if (!is_array($extGlob)) { 
  1041. throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension))); 
  1042.  
  1043. $globals[] = $extGlob; 
  1044.  
  1045. $globals[] = $this->staging->getGlobals(); 
  1046.  
  1047. return call_user_func_array('array_merge', $globals); 
  1048.  
  1049. /** 
  1050. * @internal 
  1051. */ 
  1052. protected function initExtensions() 
  1053. if ($this->extensionInitialized) { 
  1054. return; 
  1055.  
  1056. $this->parsers = new Twig_TokenParserBroker(array(), array(), false); 
  1057. $this->filters = array(); 
  1058. $this->functions = array(); 
  1059. $this->tests = array(); 
  1060. $this->visitors = array(); 
  1061. $this->unaryOperators = array(); 
  1062. $this->binaryOperators = array(); 
  1063.  
  1064. foreach ($this->extensions as $extension) { 
  1065. $this->initExtension($extension); 
  1066. $this->initExtension($this->staging); 
  1067. // Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception 
  1068. $this->extensionInitialized = true; 
  1069.  
  1070. /** 
  1071. * @internal 
  1072. */ 
  1073. protected function initExtension(Twig_ExtensionInterface $extension) 
  1074. // filters 
  1075. foreach ($extension->getFilters() as $name => $filter) { 
  1076. if ($filter instanceof Twig_SimpleFilter) { 
  1077. $name = $filter->getName(); 
  1078. } else { 
  1079. @trigger_error(sprintf('Using an instance of "%s" for filter "%s" is deprecated since version 1.21. Use Twig_SimpleFilter instead.', get_class($filter), $name), E_USER_DEPRECATED); 
  1080.  
  1081. $this->filters[$name] = $filter; 
  1082.  
  1083. // functions 
  1084. foreach ($extension->getFunctions() as $name => $function) { 
  1085. if ($function instanceof Twig_SimpleFunction) { 
  1086. $name = $function->getName(); 
  1087. } else { 
  1088. @trigger_error(sprintf('Using an instance of "%s" for function "%s" is deprecated since version 1.21. Use Twig_SimpleFunction instead.', get_class($function), $name), E_USER_DEPRECATED); 
  1089.  
  1090. $this->functions[$name] = $function; 
  1091.  
  1092. // tests 
  1093. foreach ($extension->getTests() as $name => $test) { 
  1094. if ($test instanceof Twig_SimpleTest) { 
  1095. $name = $test->getName(); 
  1096. } else { 
  1097. @trigger_error(sprintf('Using an instance of "%s" for test "%s" is deprecated since version 1.21. Use Twig_SimpleTest instead.', get_class($test), $name), E_USER_DEPRECATED); 
  1098.  
  1099. $this->tests[$name] = $test; 
  1100.  
  1101. // token parsers 
  1102. foreach ($extension->getTokenParsers() as $parser) { 
  1103. if ($parser instanceof Twig_TokenParserInterface) { 
  1104. $this->parsers->addTokenParser($parser); 
  1105. } elseif ($parser instanceof Twig_TokenParserBrokerInterface) { 
  1106. @trigger_error('Registering a Twig_TokenParserBrokerInterface instance is deprecated since version 1.21.', E_USER_DEPRECATED); 
  1107.  
  1108. $this->parsers->addTokenParserBroker($parser); 
  1109. } else { 
  1110. throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances.'); 
  1111.  
  1112. // node visitors 
  1113. foreach ($extension->getNodeVisitors() as $visitor) { 
  1114. $this->visitors[] = $visitor; 
  1115.  
  1116. // operators 
  1117. if ($operators = $extension->getOperators()) { 
  1118. if (!is_array($operators)) { 
  1119. throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', get_class($extension), is_object($operators) ? get_class($operators) : gettype($operators).(is_resource($operators) ? '' : '#'.$operators))); 
  1120.  
  1121. if (2 !== count($operators)) { 
  1122. throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', get_class($extension), count($operators))); 
  1123.  
  1124. $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]); 
  1125. $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]); 
  1126.  
  1127. /** 
  1128. * @deprecated since 1.22 (to be removed in 2.0) 
  1129. */ 
  1130. protected function writeCacheFile($file, $content) 
  1131. $this->cache->write($file, $content); 
  1132.  
  1133. private function updateOptionsHash() 
  1134. $hashParts = array_merge( 
  1135. array_keys($this->extensions),  
  1136. array( 
  1137. (int) function_exists('twig_template_get_attributes'),  
  1138. PHP_MAJOR_VERSION,  
  1139. PHP_MINOR_VERSION,  
  1140. self::VERSION,  
  1141. (int) $this->debug,  
  1142. $this->baseTemplateClass,  
  1143. (int) $this->strictVariables,  
  1144. ); 
  1145. $this->optionsHash = implode(':', $hashParts);