Просмотр файла vendor/symfony/http-kernel/Kernel.php

Размер файла: 22.38Kb
  1. <?php
  2.  
  3. /*
  4. * This file is part of the Symfony package.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11.  
  12. namespace Symfony\Component\HttpKernel;
  13.  
  14. use Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator;
  15. use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
  16. use Symfony\Component\DependencyInjection\ContainerInterface;
  17. use Symfony\Component\DependencyInjection\ContainerBuilder;
  18. use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
  19. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
  20. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  21. use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
  22. use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
  23. use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
  24. use Symfony\Component\DependencyInjection\Loader\DirectoryLoader;
  25. use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
  26. use Symfony\Component\HttpFoundation\Request;
  27. use Symfony\Component\HttpFoundation\Response;
  28. use Symfony\Component\HttpKernel\Bundle\BundleInterface;
  29. use Symfony\Component\HttpKernel\Config\EnvParametersResource;
  30. use Symfony\Component\HttpKernel\Config\FileLocator;
  31. use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
  32. use Symfony\Component\HttpKernel\DependencyInjection\AddClassesToCachePass;
  33. use Symfony\Component\Config\Loader\LoaderResolver;
  34. use Symfony\Component\Config\Loader\DelegatingLoader;
  35. use Symfony\Component\Config\ConfigCache;
  36. use Symfony\Component\ClassLoader\ClassCollectionLoader;
  37.  
  38. /**
  39. * The Kernel is the heart of the Symfony system.
  40. *
  41. * It manages an environment made of bundles.
  42. *
  43. * @author Fabien Potencier <fabien@symfony.com>
  44. */
  45. abstract class Kernel implements KernelInterface, TerminableInterface
  46. {
  47. /**
  48. * @var BundleInterface[]
  49. */
  50. protected $bundles = array();
  51.  
  52. protected $bundleMap;
  53. protected $container;
  54. protected $rootDir;
  55. protected $environment;
  56. protected $debug;
  57. protected $booted = false;
  58. protected $name;
  59. protected $startTime;
  60. protected $loadClassCache;
  61.  
  62. const VERSION = '3.1.9';
  63. const VERSION_ID = 30109;
  64. const MAJOR_VERSION = 3;
  65. const MINOR_VERSION = 1;
  66. const RELEASE_VERSION = 9;
  67. const EXTRA_VERSION = '';
  68.  
  69. const END_OF_MAINTENANCE = '01/2017';
  70. const END_OF_LIFE = '07/2017';
  71.  
  72. /**
  73. * Constructor.
  74. *
  75. * @param string $environment The environment
  76. * @param bool $debug Whether to enable debugging or not
  77. */
  78. public function __construct($environment, $debug)
  79. {
  80. $this->environment = $environment;
  81. $this->debug = (bool) $debug;
  82. $this->rootDir = $this->getRootDir();
  83. $this->name = $this->getName();
  84.  
  85. if ($this->debug) {
  86. $this->startTime = microtime(true);
  87. }
  88. }
  89.  
  90. public function __clone()
  91. {
  92. if ($this->debug) {
  93. $this->startTime = microtime(true);
  94. }
  95.  
  96. $this->booted = false;
  97. $this->container = null;
  98. }
  99.  
  100. /**
  101. * Boots the current kernel.
  102. */
  103. public function boot()
  104. {
  105. if (true === $this->booted) {
  106. return;
  107. }
  108.  
  109. if ($this->loadClassCache) {
  110. $this->doLoadClassCache($this->loadClassCache[0], $this->loadClassCache[1]);
  111. }
  112.  
  113. // init bundles
  114. $this->initializeBundles();
  115.  
  116. // init container
  117. $this->initializeContainer();
  118.  
  119. foreach ($this->getBundles() as $bundle) {
  120. $bundle->setContainer($this->container);
  121. $bundle->boot();
  122. }
  123.  
  124. $this->booted = true;
  125. }
  126.  
  127. /**
  128. * {@inheritdoc}
  129. */
  130. public function terminate(Request $request, Response $response)
  131. {
  132. if (false === $this->booted) {
  133. return;
  134. }
  135.  
  136. if ($this->getHttpKernel() instanceof TerminableInterface) {
  137. $this->getHttpKernel()->terminate($request, $response);
  138. }
  139. }
  140.  
  141. /**
  142. * {@inheritdoc}
  143. */
  144. public function shutdown()
  145. {
  146. if (false === $this->booted) {
  147. return;
  148. }
  149.  
  150. $this->booted = false;
  151.  
  152. foreach ($this->getBundles() as $bundle) {
  153. $bundle->shutdown();
  154. $bundle->setContainer(null);
  155. }
  156.  
  157. $this->container = null;
  158. }
  159.  
  160. /**
  161. * {@inheritdoc}
  162. */
  163. public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
  164. {
  165. if (false === $this->booted) {
  166. $this->boot();
  167. }
  168.  
  169. return $this->getHttpKernel()->handle($request, $type, $catch);
  170. }
  171.  
  172. /**
  173. * Gets a HTTP kernel from the container.
  174. *
  175. * @return HttpKernel
  176. */
  177. protected function getHttpKernel()
  178. {
  179. return $this->container->get('http_kernel');
  180. }
  181.  
  182. /**
  183. * {@inheritdoc}
  184. */
  185. public function getBundles()
  186. {
  187. return $this->bundles;
  188. }
  189.  
  190. /**
  191. * {@inheritdoc}
  192. */
  193. public function getBundle($name, $first = true)
  194. {
  195. if (!isset($this->bundleMap[$name])) {
  196. throw new \InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled. Maybe you forgot to add it in the registerBundles() method of your %s.php file?', $name, get_class($this)));
  197. }
  198.  
  199. if (true === $first) {
  200. return $this->bundleMap[$name][0];
  201. }
  202.  
  203. return $this->bundleMap[$name];
  204. }
  205.  
  206. /**
  207. * {@inheritdoc}
  208. *
  209. * @throws \RuntimeException if a custom resource is hidden by a resource in a derived bundle
  210. */
  211. public function locateResource($name, $dir = null, $first = true)
  212. {
  213. if ('@' !== $name[0]) {
  214. throw new \InvalidArgumentException(sprintf('A resource name must start with @ ("%s" given).', $name));
  215. }
  216.  
  217. if (false !== strpos($name, '..')) {
  218. throw new \RuntimeException(sprintf('File name "%s" contains invalid characters (..).', $name));
  219. }
  220.  
  221. $bundleName = substr($name, 1);
  222. $path = '';
  223. if (false !== strpos($bundleName, '/')) {
  224. list($bundleName, $path) = explode('/', $bundleName, 2);
  225. }
  226.  
  227. $isResource = 0 === strpos($path, 'Resources') && null !== $dir;
  228. $overridePath = substr($path, 9);
  229. $resourceBundle = null;
  230. $bundles = $this->getBundle($bundleName, false);
  231. $files = array();
  232.  
  233. foreach ($bundles as $bundle) {
  234. if ($isResource && file_exists($file = $dir.'/'.$bundle->getName().$overridePath)) {
  235. if (null !== $resourceBundle) {
  236. throw new \RuntimeException(sprintf('"%s" resource is hidden by a resource from the "%s" derived bundle. Create a "%s" file to override the bundle resource.',
  237. $file,
  238. $resourceBundle,
  239. $dir.'/'.$bundles[0]->getName().$overridePath
  240. ));
  241. }
  242.  
  243. if ($first) {
  244. return $file;
  245. }
  246. $files[] = $file;
  247. }
  248.  
  249. if (file_exists($file = $bundle->getPath().'/'.$path)) {
  250. if ($first && !$isResource) {
  251. return $file;
  252. }
  253. $files[] = $file;
  254. $resourceBundle = $bundle->getName();
  255. }
  256. }
  257.  
  258. if (count($files) > 0) {
  259. return $first && $isResource ? $files[0] : $files;
  260. }
  261.  
  262. throw new \InvalidArgumentException(sprintf('Unable to find file "%s".', $name));
  263. }
  264.  
  265. /**
  266. * {@inheritdoc}
  267. */
  268. public function getName()
  269. {
  270. if (null === $this->name) {
  271. $this->name = preg_replace('/[^a-zA-Z0-9_]+/', '', basename($this->rootDir));
  272. }
  273.  
  274. return $this->name;
  275. }
  276.  
  277. /**
  278. * {@inheritdoc}
  279. */
  280. public function getEnvironment()
  281. {
  282. return $this->environment;
  283. }
  284.  
  285. /**
  286. * {@inheritdoc}
  287. */
  288. public function isDebug()
  289. {
  290. return $this->debug;
  291. }
  292.  
  293. /**
  294. * {@inheritdoc}
  295. */
  296. public function getRootDir()
  297. {
  298. if (null === $this->rootDir) {
  299. $r = new \ReflectionObject($this);
  300. $this->rootDir = dirname($r->getFileName());
  301. }
  302.  
  303. return $this->rootDir;
  304. }
  305.  
  306. /**
  307. * {@inheritdoc}
  308. */
  309. public function getContainer()
  310. {
  311. return $this->container;
  312. }
  313.  
  314. /**
  315. * Loads the PHP class cache.
  316. *
  317. * This methods only registers the fact that you want to load the cache classes.
  318. * The cache will actually only be loaded when the Kernel is booted.
  319. *
  320. * That optimization is mainly useful when using the HttpCache class in which
  321. * case the class cache is not loaded if the Response is in the cache.
  322. *
  323. * @param string $name The cache name prefix
  324. * @param string $extension File extension of the resulting file
  325. */
  326. public function loadClassCache($name = 'classes', $extension = '.php')
  327. {
  328. $this->loadClassCache = array($name, $extension);
  329. }
  330.  
  331. /**
  332. * Used internally.
  333. */
  334. public function setClassCache(array $classes)
  335. {
  336. file_put_contents($this->getCacheDir().'/classes.map', sprintf('<?php return %s;', var_export($classes, true)));
  337. }
  338.  
  339. /**
  340. * {@inheritdoc}
  341. */
  342. public function getStartTime()
  343. {
  344. return $this->debug ? $this->startTime : -INF;
  345. }
  346.  
  347. /**
  348. * {@inheritdoc}
  349. */
  350. public function getCacheDir()
  351. {
  352. return $this->rootDir.'/cache/'.$this->environment;
  353. }
  354.  
  355. /**
  356. * {@inheritdoc}
  357. */
  358. public function getLogDir()
  359. {
  360. return $this->rootDir.'/logs';
  361. }
  362.  
  363. /**
  364. * {@inheritdoc}
  365. */
  366. public function getCharset()
  367. {
  368. return 'UTF-8';
  369. }
  370.  
  371. protected function doLoadClassCache($name, $extension)
  372. {
  373. if (!$this->booted && is_file($this->getCacheDir().'/classes.map')) {
  374. ClassCollectionLoader::load(include($this->getCacheDir().'/classes.map'), $this->getCacheDir(), $name, $this->debug, false, $extension);
  375. }
  376. }
  377.  
  378. /**
  379. * Initializes the data structures related to the bundle management.
  380. *
  381. * - the bundles property maps a bundle name to the bundle instance,
  382. * - the bundleMap property maps a bundle name to the bundle inheritance hierarchy (most derived bundle first).
  383. *
  384. * @throws \LogicException if two bundles share a common name
  385. * @throws \LogicException if a bundle tries to extend a non-registered bundle
  386. * @throws \LogicException if a bundle tries to extend itself
  387. * @throws \LogicException if two bundles extend the same ancestor
  388. */
  389. protected function initializeBundles()
  390. {
  391. // init bundles
  392. $this->bundles = array();
  393. $topMostBundles = array();
  394. $directChildren = array();
  395.  
  396. foreach ($this->registerBundles() as $bundle) {
  397. $name = $bundle->getName();
  398. if (isset($this->bundles[$name])) {
  399. throw new \LogicException(sprintf('Trying to register two bundles with the same name "%s"', $name));
  400. }
  401. $this->bundles[$name] = $bundle;
  402.  
  403. if ($parentName = $bundle->getParent()) {
  404. if (isset($directChildren[$parentName])) {
  405. throw new \LogicException(sprintf('Bundle "%s" is directly extended by two bundles "%s" and "%s".', $parentName, $name, $directChildren[$parentName]));
  406. }
  407. if ($parentName == $name) {
  408. throw new \LogicException(sprintf('Bundle "%s" can not extend itself.', $name));
  409. }
  410. $directChildren[$parentName] = $name;
  411. } else {
  412. $topMostBundles[$name] = $bundle;
  413. }
  414. }
  415.  
  416. // look for orphans
  417. if (!empty($directChildren) && count($diff = array_diff_key($directChildren, $this->bundles))) {
  418. $diff = array_keys($diff);
  419.  
  420. throw new \LogicException(sprintf('Bundle "%s" extends bundle "%s", which is not registered.', $directChildren[$diff[0]], $diff[0]));
  421. }
  422.  
  423. // inheritance
  424. $this->bundleMap = array();
  425. foreach ($topMostBundles as $name => $bundle) {
  426. $bundleMap = array($bundle);
  427. $hierarchy = array($name);
  428.  
  429. while (isset($directChildren[$name])) {
  430. $name = $directChildren[$name];
  431. array_unshift($bundleMap, $this->bundles[$name]);
  432. $hierarchy[] = $name;
  433. }
  434.  
  435. foreach ($hierarchy as $hierarchyBundle) {
  436. $this->bundleMap[$hierarchyBundle] = $bundleMap;
  437. array_pop($bundleMap);
  438. }
  439. }
  440. }
  441.  
  442. /**
  443. * Gets the container class.
  444. *
  445. * @return string The container class
  446. */
  447. protected function getContainerClass()
  448. {
  449. return $this->name.ucfirst($this->environment).($this->debug ? 'Debug' : '').'ProjectContainer';
  450. }
  451.  
  452. /**
  453. * Gets the container's base class.
  454. *
  455. * All names except Container must be fully qualified.
  456. *
  457. * @return string
  458. */
  459. protected function getContainerBaseClass()
  460. {
  461. return 'Container';
  462. }
  463.  
  464. /**
  465. * Initializes the service container.
  466. *
  467. * The cached version of the service container is used when fresh, otherwise the
  468. * container is built.
  469. */
  470. protected function initializeContainer()
  471. {
  472. $class = $this->getContainerClass();
  473. $cache = new ConfigCache($this->getCacheDir().'/'.$class.'.php', $this->debug);
  474. $fresh = true;
  475. if (!$cache->isFresh()) {
  476. $container = $this->buildContainer();
  477. $container->compile();
  478. $this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());
  479.  
  480. $fresh = false;
  481. }
  482.  
  483. require_once $cache->getPath();
  484.  
  485. $this->container = new $class();
  486. $this->container->set('kernel', $this);
  487.  
  488. if (!$fresh && $this->container->has('cache_warmer')) {
  489. $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir'));
  490. }
  491. }
  492.  
  493. /**
  494. * Returns the kernel parameters.
  495. *
  496. * @return array An array of kernel parameters
  497. */
  498. protected function getKernelParameters()
  499. {
  500. $bundles = array();
  501. $bundlesMetadata = array();
  502.  
  503. foreach ($this->bundles as $name => $bundle) {
  504. $bundles[$name] = get_class($bundle);
  505. $bundlesMetadata[$name] = array(
  506. 'parent' => $bundle->getParent(),
  507. 'path' => $bundle->getPath(),
  508. 'namespace' => $bundle->getNamespace(),
  509. );
  510. }
  511.  
  512. return array_merge(
  513. array(
  514. 'kernel.root_dir' => realpath($this->rootDir) ?: $this->rootDir,
  515. 'kernel.environment' => $this->environment,
  516. 'kernel.debug' => $this->debug,
  517. 'kernel.name' => $this->name,
  518. 'kernel.cache_dir' => realpath($this->getCacheDir()) ?: $this->getCacheDir(),
  519. 'kernel.logs_dir' => realpath($this->getLogDir()) ?: $this->getLogDir(),
  520. 'kernel.bundles' => $bundles,
  521. 'kernel.bundles_metadata' => $bundlesMetadata,
  522. 'kernel.charset' => $this->getCharset(),
  523. 'kernel.container_class' => $this->getContainerClass(),
  524. ),
  525. $this->getEnvParameters()
  526. );
  527. }
  528.  
  529. /**
  530. * Gets the environment parameters.
  531. *
  532. * Only the parameters starting with "SYMFONY__" are considered.
  533. *
  534. * @return array An array of parameters
  535. */
  536. protected function getEnvParameters()
  537. {
  538. $parameters = array();
  539. foreach ($_SERVER as $key => $value) {
  540. if (0 === strpos($key, 'SYMFONY__')) {
  541. $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value;
  542. }
  543. }
  544.  
  545. return $parameters;
  546. }
  547.  
  548. /**
  549. * Builds the service container.
  550. *
  551. * @return ContainerBuilder The compiled service container
  552. *
  553. * @throws \RuntimeException
  554. */
  555. protected function buildContainer()
  556. {
  557. foreach (array('cache' => $this->getCacheDir(), 'logs' => $this->getLogDir()) as $name => $dir) {
  558. if (!is_dir($dir)) {
  559. if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
  560. throw new \RuntimeException(sprintf("Unable to create the %s directory (%s)\n", $name, $dir));
  561. }
  562. } elseif (!is_writable($dir)) {
  563. throw new \RuntimeException(sprintf("Unable to write in the %s directory (%s)\n", $name, $dir));
  564. }
  565. }
  566.  
  567. $container = $this->getContainerBuilder();
  568. $container->addObjectResource($this);
  569. $this->prepareContainer($container);
  570.  
  571. if (null !== $cont = $this->registerContainerConfiguration($this->getContainerLoader($container))) {
  572. $container->merge($cont);
  573. }
  574.  
  575. $container->addCompilerPass(new AddClassesToCachePass($this));
  576. $container->addResource(new EnvParametersResource('SYMFONY__'));
  577.  
  578. return $container;
  579. }
  580.  
  581. /**
  582. * Prepares the ContainerBuilder before it is compiled.
  583. *
  584. * @param ContainerBuilder $container A ContainerBuilder instance
  585. */
  586. protected function prepareContainer(ContainerBuilder $container)
  587. {
  588. $extensions = array();
  589. foreach ($this->bundles as $bundle) {
  590. if ($extension = $bundle->getContainerExtension()) {
  591. $container->registerExtension($extension);
  592. $extensions[] = $extension->getAlias();
  593. }
  594.  
  595. if ($this->debug) {
  596. $container->addObjectResource($bundle);
  597. }
  598. }
  599. foreach ($this->bundles as $bundle) {
  600. $bundle->build($container);
  601. }
  602.  
  603. // ensure these extensions are implicitly loaded
  604. $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions));
  605. }
  606.  
  607. /**
  608. * Gets a new ContainerBuilder instance used to build the service container.
  609. *
  610. * @return ContainerBuilder
  611. */
  612. protected function getContainerBuilder()
  613. {
  614. $container = new ContainerBuilder(new ParameterBag($this->getKernelParameters()));
  615.  
  616. if (class_exists('ProxyManager\Configuration') && class_exists('Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator')) {
  617. $container->setProxyInstantiator(new RuntimeInstantiator());
  618. }
  619.  
  620. return $container;
  621. }
  622.  
  623. /**
  624. * Dumps the service container to PHP code in the cache.
  625. *
  626. * @param ConfigCache $cache The config cache
  627. * @param ContainerBuilder $container The service container
  628. * @param string $class The name of the class to generate
  629. * @param string $baseClass The name of the container's base class
  630. */
  631. protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container, $class, $baseClass)
  632. {
  633. // cache the container
  634. $dumper = new PhpDumper($container);
  635.  
  636. if (class_exists('ProxyManager\Configuration') && class_exists('Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper')) {
  637. $dumper->setProxyDumper(new ProxyDumper(md5($cache->getPath())));
  638. }
  639.  
  640. $content = $dumper->dump(array('class' => $class, 'base_class' => $baseClass, 'file' => $cache->getPath(), 'debug' => $this->debug));
  641.  
  642. $cache->write($content, $container->getResources());
  643. }
  644.  
  645. /**
  646. * Returns a loader for the container.
  647. *
  648. * @param ContainerInterface $container The service container
  649. *
  650. * @return DelegatingLoader The loader
  651. */
  652. protected function getContainerLoader(ContainerInterface $container)
  653. {
  654. $locator = new FileLocator($this);
  655. $resolver = new LoaderResolver(array(
  656. new XmlFileLoader($container, $locator),
  657. new YamlFileLoader($container, $locator),
  658. new IniFileLoader($container, $locator),
  659. new PhpFileLoader($container, $locator),
  660. new DirectoryLoader($container, $locator),
  661. new ClosureLoader($container),
  662. ));
  663.  
  664. return new DelegatingLoader($resolver);
  665. }
  666.  
  667. /**
  668. * Removes comments from a PHP source string.
  669. *
  670. * We don't use the PHP php_strip_whitespace() function
  671. * as we want the content to be readable and well-formatted.
  672. *
  673. * @param string $source A PHP string
  674. *
  675. * @return string The PHP string with the comments removed
  676. */
  677. public static function stripComments($source)
  678. {
  679. if (!function_exists('token_get_all')) {
  680. return $source;
  681. }
  682.  
  683. $rawChunk = '';
  684. $output = '';
  685. $tokens = token_get_all($source);
  686. $ignoreSpace = false;
  687. for ($i = 0; isset($tokens[$i]); ++$i) {
  688. $token = $tokens[$i];
  689. if (!isset($token[1]) || 'b"' === $token) {
  690. $rawChunk .= $token;
  691. } elseif (T_START_HEREDOC === $token[0]) {
  692. $output .= $rawChunk.$token[1];
  693. do {
  694. $token = $tokens[++$i];
  695. $output .= isset($token[1]) && 'b"' !== $token ? $token[1] : $token;
  696. } while ($token[0] !== T_END_HEREDOC);
  697. $rawChunk = '';
  698. } elseif (T_WHITESPACE === $token[0]) {
  699. if ($ignoreSpace) {
  700. $ignoreSpace = false;
  701.  
  702. continue;
  703. }
  704.  
  705. // replace multiple new lines with a single newline
  706. $rawChunk .= preg_replace(array('/\n{2,}/S'), "\n", $token[1]);
  707. } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
  708. $ignoreSpace = true;
  709. } else {
  710. $rawChunk .= $token[1];
  711.  
  712. // The PHP-open tag already has a new-line
  713. if (T_OPEN_TAG === $token[0]) {
  714. $ignoreSpace = true;
  715. }
  716. }
  717. }
  718.  
  719. $output .= $rawChunk;
  720.  
  721. if (PHP_VERSION_ID >= 70000) {
  722. // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
  723. unset($tokens, $rawChunk);
  724. gc_mem_caches();
  725. }
  726.  
  727. return $output;
  728. }
  729.  
  730. public function serialize()
  731. {
  732. return serialize(array($this->environment, $this->debug));
  733. }
  734.  
  735. public function unserialize($data)
  736. {
  737. list($environment, $debug) = unserialize($data);
  738.  
  739. $this->__construct($environment, $debug);
  740. }
  741. }