class DrupalKernel

The DrupalKernel class is the core of Drupal itself.

This class is responsible for building the Dependency Injection Container and also deals with the registration of bundles. It allows registered bundles to add their services to the container. Core provides the CoreBundle, which adds the services required for all core subsystems. Each module can then add its own bundle, i.e. a subclass of Symfony\Component\HttpKernel\Bundle, to register services to the container.

Hierarchy

Expanded class hierarchy of DrupalKernel

11 files declare their use of DrupalKernel
bootstrap.inc in drupal/core/includes/bootstrap.inc
Functions that need to be loaded on every Drupal request.
DrupalKernelTest.php in drupal/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php
Contains Drupal\system\Tests\DrupalKernel\DrupalKernelTest.
DrupalUnitTestBase.php in drupal/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
Contains Drupal\simpletest\DrupalUnitTestBase.
IgnoreSlaveSubscriberTest.php in drupal/core/modules/system/lib/Drupal/system/Tests/System/IgnoreSlaveSubscriberTest.php
install.core.inc in drupal/core/includes/install.core.inc
API functions for installing Drupal.

... See full list

4 string references to 'DrupalKernel'
ContentNegotiationTest::getInfo in drupal/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/ContentNegotiationTest.php
DrupalKernel::boot in drupal/core/lib/Drupal/Core/DrupalKernel.php
Overrides Kernel::boot().
DrupalKernelTest::getInfo in drupal/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php
ServiceDestructionTest::getInfo in drupal/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/ServiceDestructionTest.php

File

drupal/core/lib/Drupal/Core/DrupalKernel.php, line 31
Definition of Drupal\Core\DrupalKernel.

Namespace

Drupal\Core
View source
class DrupalKernel extends Kernel implements DrupalKernelInterface {

  /**
   * Holds the list of enabled modules.
   *
   * @var array
   *   An associative array whose keys are module names and whose values are
   *   ignored.
   */
  protected $moduleList;

  /**
   * Holds an updated list of enabled modules.
   *
   * @var array
   *   An associative array whose keys are module names and whose values are
   *   ignored.
   */
  protected $newModuleList;

  /**
   * An array of module data objects.
   *
   * The data objects have the same data structure as returned by
   * file_scan_directory() but only the uri property is used.
   *
   * @var array
   */
  protected $moduleData = array();

  /**
   * PHP code storage object to use for the compiled container.
   *
   * @var \Drupal\Component\PhpStorage\PhpStorageInterface
   */
  protected $storage;

  /**
   * The classloader object.
   *
   * @var \Symfony\Component\ClassLoader\ClassLoader
   */
  protected $classLoader;

  /**
   * Config storage object used for reading enabled modules configuration.
   *
   * @var \Drupal\Core\Config\StorageInterface
   */
  protected $configStorage;

  /**
   * The list of the classnames of the bundles in this kernel.
   *
   * @var array
   */
  protected $bundleClasses;

  /**
   * Whether the container can be dumped.
   *
   * @var bool
   */
  protected $allowDumping;

  /**
   * Whether the container needs to be dumped once booting is complete.
   *
   * @var bool
   */
  protected $containerNeedsDumping;

  /**
   * Holds the list of YAML files containing service definitions.
   *
   * @var array
   */
  protected $serviceYamls;

  /**
   * Constructs a DrupalKernel object.
   *
   * @param string $environment
   *   String indicating the environment, e.g. 'prod' or 'dev'. Used by
   *   Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use
   *   this value currently. Pass 'prod'.
   * @param bool $debug
   *   Boolean indicating whether we are in debug mode. Used by
   *   Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use
   *   this value currently. Pass TRUE.
   * @param \Symfony\Component\ClassLoader\ClassLoader $class_loader
   *   (optional) The classloader is only used if $storage is not given or
   *   the load from storage fails and a container rebuild is required. In
   *   this case, the loaded modules will be registered with this loader in
   *   order to be able to find the module bundles.
   * @param bool $allow_dumping
   *   (optional) FALSE to stop the container from being written to or read
   *   from disk. Defaults to TRUE.
   */
  public function __construct($environment, $debug, ClassLoader $class_loader, $allow_dumping = TRUE) {
    parent::__construct($environment, $debug);
    $this->classLoader = $class_loader;
    $this->allowDumping = $allow_dumping;
  }

  /**
   * {@inheritdoc}
   */
  public function serialize() {
    return serialize(array(
      $this->environment,
      $this->debug,
      $this->classLoader,
      $this->allowDumping,
    ));
  }

  /**
   * {@inheritdoc}
   */
  public function unserialize($data) {
    list($environment, $debug, $class_loader, $allow_dumping) = unserialize($data);
    $this
      ->__construct($environment, $debug, $class_loader, $allow_dumping);
  }

  /**
   * Overrides Kernel::init().
   */
  public function init() {

    // Intentionally empty. The sole purpose is to not execute Kernel::init(),
    // since that overrides/breaks Drupal's current error handling.
    // @todo Investigate whether it is possible to migrate Drupal's error
    //   handling to the one of Kernel without losing functionality.
  }

  /**
   * Overrides Kernel::boot().
   */
  public function boot() {
    if ($this->booted) {
      return;
    }
    $this
      ->initializeContainer();
    $this->booted = TRUE;
    if ($this->containerNeedsDumping && !$this
      ->dumpDrupalContainer($this->container, $this
      ->getContainerBaseClass())) {
      watchdog('DrupalKernel', 'Container cannot be written to disk');
    }
  }

  /**
   * Returns an array of available bundles.
   *
   * @return array
   *   The available bundles.
   */
  public function registerBundles() {
    $this->configStorage = BootstrapConfigStorageFactory::get();
    $bundles = array(
      new CoreBundle(),
    );
    $this->serviceYamls = array(
      'core/core.services.yml',
    );
    $this->bundleClasses = array(
      'Drupal\\Core\\CoreBundle',
    );

    // Ensure we know what modules are enabled and that their namespaces are
    // registered.
    if (!isset($this->moduleList)) {
      $module_list = $this->configStorage
        ->read('system.module');
      $this->moduleList = isset($module_list['enabled']) ? $module_list['enabled'] : array();
    }
    $module_filenames = $this
      ->getModuleFileNames();
    $this
      ->registerNamespaces($this
      ->getModuleNamespaces($module_filenames));

    // Load each module's bundle class.
    foreach ($this->moduleList as $module => $weight) {
      $camelized = ContainerBuilder::camelize($module);
      $class = "Drupal\\{$module}\\{$camelized}Bundle";
      if (class_exists($class)) {
        $bundles[] = new $class();
        $this->bundleClasses[] = $class;
      }
      $filename = dirname($module_filenames[$module]) . "/{$module}.services.yml";
      if (file_exists($filename)) {
        $this->serviceYamls[] = $filename;
      }
    }

    // Add site specific or test bundles.
    if (!empty($GLOBALS['conf']['container_bundles'])) {
      foreach ($GLOBALS['conf']['container_bundles'] as $class) {
        $bundles[] = new $class();
        $this->bundleClasses[] = $class;
      }
    }

    // Add site specific or test YAMLs.
    if (!empty($GLOBALS['conf']['container_yamls'])) {
      $this->serviceYamls = array_merge($this->serviceYamls, $GLOBALS['conf']['container_yamls']);
    }
    return $bundles;
  }

  /**
   * Returns module data on the filesystem.
   *
   * @param $module
   *   The name of the module.
   *
   * @return \stdClass|bool
   *   Returns a stdClass object if the module data is found containing at
   *   least an uri property with the module path, for example
   *   core/modules/user/user.module.
   */
  protected function moduleData($module) {
    if (!$this->moduleData) {

      // First, find profiles.
      $profiles_scanner = new SystemListing();
      $all_profiles = $profiles_scanner
        ->scan('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\\.profile$/', 'profiles');
      $profiles = array_keys(array_intersect_key($this->moduleList, $all_profiles));

      // If a module is within a profile directory but specifies another
      // profile for testing, it needs to be found in the parent profile.
      if (($parent_profile_config = $this->configStorage
        ->read('simpletest.settings')) && isset($parent_profile_config['parent_profile']) && $parent_profile_config['parent_profile'] != $profiles[0]) {

        // In case both profile directories contain the same extension, the
        // actual profile always has precedence.
        array_unshift($profiles, $parent_profile_config['parent_profile']);
      }

      // Now find modules.
      $modules_scanner = new SystemListing($profiles);
      $this->moduleData = $all_profiles + $modules_scanner
        ->scan('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\\.module$/', 'modules');
    }
    return isset($this->moduleData[$module]) ? $this->moduleData[$module] : FALSE;
  }

  /**
   * Implements Drupal\Core\DrupalKernelInterface::updateModules().
   *
   * @todo Remove obsolete $module_list parameter. Only $module_filenames is
   *   needed.
   */
  public function updateModules(array $module_list, array $module_filenames = array()) {
    $this->newModuleList = $module_list;
    foreach ($module_filenames as $module => $filename) {
      $this->moduleData[$module] = (object) array(
        'uri' => $filename,
      );
    }

    // If we haven't yet booted, we don't need to do anything: the new module
    // list will take effect when boot() is called. If we have already booted,
    // then reboot in order to refresh the bundle list and container.
    if ($this->booted) {
      $this->booted = FALSE;
      $this
        ->boot();
    }
  }

  /**
   * Returns the classname based on environment, debug and testing prefix.
   *
   * @return string
   *   The class name.
   */
  protected function getClassName() {
    $parts = array(
      'service_container',
      $this->environment,
      $this->debug,
    );

    // Make sure to use a testing-specific container even in the parent site.
    if (!empty($GLOBALS['drupal_test_info']['test_run_id'])) {
      $parts[] = $GLOBALS['drupal_test_info']['test_run_id'];
    }
    elseif ($prefix = drupal_valid_test_ua()) {
      $parts[] = $prefix;
    }
    return implode('_', $parts);
  }

  /**
   * Initializes the service container.
   */
  protected function initializeContainer() {
    $persist = $this
      ->getServicesToPersist();

    // If we are rebuilding the kernel and we are in a request scope, store
    // request info so we can add them back after the rebuild.
    if (isset($this->container) && $this->container
      ->hasScope('request')) {
      $request = $this->container
        ->get('request');
    }
    $this->container = NULL;
    $class = $this
      ->getClassName();
    $cache_file = $class . '.php';
    if ($this->allowDumping) {

      // First, try to load.
      if (!class_exists($class, FALSE)) {
        $this
          ->storage()
          ->load($cache_file);
      }

      // If the load succeeded or the class already existed, use it.
      if (class_exists($class, FALSE)) {
        $fully_qualified_class_name = '\\' . $class;
        $this->container = new $fully_qualified_class_name();
        $this
          ->persistServices($persist);
      }
    }

    // First check whether the list of modules changed in this request.
    if (isset($this->newModuleList)) {
      if (isset($this->container) && isset($this->moduleList) && array_keys($this->moduleList) !== array_keys($this->newModuleList)) {
        unset($this->container);
      }
      $this->moduleList = $this->newModuleList;
      unset($this->newModuleList);
    }

    // Second, check if some other request -- for example on another web
    // frontend or during the installer -- changed the list of enabled modules.
    if (isset($this->container)) {

      // All namespaces must be registered before we attempt to use any service
      // from the container.
      $container_modules = $this->container
        ->getParameter('container.modules');
      $namespaces_before = $this->classLoader
        ->getPrefixes();
      $this
        ->registerNamespaces($this
        ->getModuleNamespaces($container_modules));

      // If 'container.modules' is wrong, the container must be rebuilt.
      if (!isset($this->moduleList)) {
        $this->moduleList = $this->container
          ->get('config.factory')
          ->get('system.module')
          ->load()
          ->get('enabled');
      }
      if (array_keys($this->moduleList) !== array_keys($container_modules)) {
        $persist = $this
          ->getServicesToPersist();
        unset($this->container);

        // Revert the class loader to its prior state. However,
        // registerNamespaces() performs a merge rather than replace, so to
        // effectively remove erroneous registrations, we must replace them with
        // empty arrays.
        $namespaces_after = $this->classLoader
          ->getPrefixes();
        $namespaces_before += array_fill_keys(array_diff(array_keys($namespaces_after), array_keys($namespaces_before)), array());
        $this
          ->registerNamespaces($namespaces_before);
      }
    }
    if (!isset($this->container)) {
      $this->container = $this
        ->buildContainer();
      $this
        ->persistServices($persist);

      // The namespaces are marked as persistent, so objects like the annotated
      // class discovery still has the right object. We may have updated the
      // list of modules, so set it.
      if ($this->container
        ->initialized('container.namespaces')) {
        $this->container
          ->get('container.namespaces')
          ->exchangeArray($this->container
          ->getParameter('container.namespaces'));
      }
      if ($this->allowDumping) {
        $this->containerNeedsDumping = TRUE;
      }
    }
    $this->container
      ->set('kernel', $this);

    // Set the class loader which was registered as a synthetic service.
    $this->container
      ->set('class_loader', $this->classLoader);

    // If we have a request set it back to the new container.
    if (isset($request)) {
      $this->container
        ->enterScope('request');
      $this->container
        ->set('request', $request);
    }
    \Drupal::setContainer($this->container);
  }

  /**
   * Returns service instances to persist from an old container to a new one.
   */
  protected function getServicesToPersist() {
    $persist = array();
    if (isset($this->container)) {
      foreach ($this->container
        ->getParameter('persistIds') as $id) {

        // It's pointless to persist services not yet initialized.
        if ($this->container
          ->initialized($id)) {
          $persist[$id] = $this->container
            ->get($id);
        }
      }
    }
    return $persist;
  }

  /**
   * Moves persistent service instances into a new container.
   */
  protected function persistServices(array $persist) {
    foreach ($persist as $id => $object) {

      // Do not override services already set() on the new container, for
      // example 'service_container'.
      if (!$this->container
        ->initialized($id)) {
        $this->container
          ->set($id, $object);
      }
    }
  }

  /**
   * Builds the service container.
   *
   * @return ContainerBuilder The compiled service container
   */
  protected function buildContainer() {
    $this
      ->initializeBundles();
    $container = $this
      ->getContainerBuilder();
    $container
      ->setParameter('container.bundles', $this->bundleClasses);
    $container
      ->setParameter('container.modules', $this
      ->getModuleFileNames());

    // Get a list of namespaces and put it onto the container.
    $namespaces = $this
      ->getModuleNamespaces($this
      ->getModuleFileNames());

    // Add all components in \Drupal\Core and \Drupal\Component that have a
    // Plugin directory.
    foreach (array(
      'Core',
      'Component',
    ) as $parent_directory) {
      $path = DRUPAL_ROOT . '/core/lib/Drupal/' . $parent_directory;
      foreach (new \DirectoryIterator($path) as $component) {
        if (!$component
          ->isDot() && is_dir($component
          ->getPathname() . '/Plugin')) {
          $namespaces['Drupal\\' . $parent_directory . '\\' . $component
            ->getFilename()] = DRUPAL_ROOT . '/core/lib';
        }
      }
    }
    $container
      ->setParameter('container.namespaces', $namespaces);

    // Register synthetic services.
    $container
      ->register('class_loader', 'Symfony\\Component\\ClassLoader\\ClassLoader')
      ->setSynthetic(TRUE);
    $container
      ->register('kernel', 'Symfony\\Component\\HttpKernel\\KernelInterface')
      ->setSynthetic(TRUE);
    $container
      ->register('service_container', 'Symfony\\Component\\DependencyInjection\\ContainerInterface')
      ->setSynthetic(TRUE);
    $yaml_loader = new YamlFileLoader($container);
    foreach ($this->serviceYamls as $filename) {
      $yaml_loader
        ->load($filename);
    }
    foreach ($this->bundles as $bundle) {
      $bundle
        ->build($container);
    }

    // Identify all services whose instances should be persisted when rebuilding
    // the container during the lifetime of the kernel (e.g., during a kernel
    // reboot). Include synthetic services, because by definition, they cannot
    // be automatically reinstantiated. Also include services tagged to persist.
    $persist_ids = array();
    foreach ($container
      ->getDefinitions() as $id => $definition) {
      if ($definition
        ->isSynthetic() || $definition
        ->getTag('persist')) {
        $persist_ids[] = $id;
      }
    }
    $container
      ->setParameter('persistIds', $persist_ids);
    $container
      ->compile();
    return $container;
  }

  /**
   * Gets a new ContainerBuilder instance used to build the service container.
   *
   * @return ContainerBuilder
   */
  protected function getContainerBuilder() {
    return new ContainerBuilder(new ParameterBag($this
      ->getKernelParameters()));
  }

  /**
   * Dumps the service container to PHP code in the config directory.
   *
   * This method is based on the dumpContainer method in the parent class, but
   * that method is reliant on the Config component which we do not use here.
   *
   * @param ContainerBuilder $container
   *   The service container.
   * @param string $baseClass
   *   The name of the container's base class
   *
   * @return bool
   *   TRUE if the container was successfully dumped to disk.
   */
  protected function dumpDrupalContainer(ContainerBuilder $container, $baseClass) {
    if (!$this
      ->storage()
      ->writeable()) {
      return FALSE;
    }

    // Cache the container.
    $dumper = new PhpDumper($container);
    $class = $this
      ->getClassName();
    $content = $dumper
      ->dump(array(
      'class' => $class,
      'base_class' => $baseClass,
    ));
    return $this
      ->storage()
      ->save($class . '.php', $content);
  }

  /**
   * Overrides and eliminates this method from the parent class. Do not use.
   *
   * This method is part of the KernelInterface interface, but takes an object
   * implementing LoaderInterface as its only parameter. This is part of the
   * Config compoment from Symfony, which is not provided by Drupal core.
   *
   * Modules wishing to provide an extension to this class which uses this
   * method are responsible for ensuring the Config component exists.
   */
  public function registerContainerConfiguration(LoaderInterface $loader) {
  }

  /**
   * Gets the PHP code storage object to use for the compiled container.
   *
   * @return \Drupal\Component\PhpStorage\PhpStorageInterface
   */
  protected function storage() {
    if (!isset($this->storage)) {
      $this->storage = PhpStorageFactory::get('service_container');
    }
    return $this->storage;
  }

  /**
   * Returns the file name for each enabled module.
   */
  protected function getModuleFileNames() {
    $filenames = array();
    foreach ($this->moduleList as $module => $weight) {
      if ($data = $this
        ->moduleData($module)) {
        $filenames[$module] = $data->uri;
      }
    }
    return $filenames;
  }

  /**
   * Gets the namespaces of each enabled module.
   */
  protected function getModuleNamespaces($moduleFileNames) {
    $namespaces = array();
    foreach ($moduleFileNames as $module => $filename) {
      $namespaces["Drupal\\{$module}"] = DRUPAL_ROOT . '/' . dirname($filename) . '/lib';
    }
    return $namespaces;
  }

  /**
   * Registers a list of namespaces.
   */
  protected function registerNamespaces(array $namespaces = array()) {
    $this->classLoader
      ->addPrefixes($namespaces);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DrupalKernel::$allowDumping protected property Whether the container can be dumped.
DrupalKernel::$bundleClasses protected property The list of the classnames of the bundles in this kernel.
DrupalKernel::$classLoader protected property The classloader object.
DrupalKernel::$configStorage protected property Config storage object used for reading enabled modules configuration.
DrupalKernel::$containerNeedsDumping protected property Whether the container needs to be dumped once booting is complete.
DrupalKernel::$moduleData protected property An array of module data objects.
DrupalKernel::$moduleList protected property Holds the list of enabled modules.
DrupalKernel::$newModuleList protected property Holds an updated list of enabled modules.
DrupalKernel::$serviceYamls protected property Holds the list of YAML files containing service definitions.
DrupalKernel::$storage protected property PHP code storage object to use for the compiled container.
DrupalKernel::boot public function Overrides Kernel::boot(). Overrides Kernel::boot
DrupalKernel::buildContainer protected function Builds the service container. Overrides Kernel::buildContainer
DrupalKernel::dumpDrupalContainer protected function Dumps the service container to PHP code in the config directory.
DrupalKernel::getClassName protected function Returns the classname based on environment, debug and testing prefix.
DrupalKernel::getContainerBuilder protected function Gets a new ContainerBuilder instance used to build the service container. Overrides Kernel::getContainerBuilder
DrupalKernel::getModuleFileNames protected function Returns the file name for each enabled module.
DrupalKernel::getModuleNamespaces protected function Gets the namespaces of each enabled module.
DrupalKernel::getServicesToPersist protected function Returns service instances to persist from an old container to a new one.
DrupalKernel::init public function Overrides Kernel::init(). Overrides Kernel::init
DrupalKernel::initializeContainer protected function Initializes the service container. Overrides Kernel::initializeContainer
DrupalKernel::moduleData protected function Returns module data on the filesystem.
DrupalKernel::persistServices protected function Moves persistent service instances into a new container.
DrupalKernel::registerBundles public function Returns an array of available bundles. Overrides KernelInterface::registerBundles
DrupalKernel::registerContainerConfiguration public function Overrides and eliminates this method from the parent class. Do not use. Overrides KernelInterface::registerContainerConfiguration
DrupalKernel::registerNamespaces protected function Registers a list of namespaces.
DrupalKernel::serialize public function Overrides Kernel::serialize
DrupalKernel::storage protected function Gets the PHP code storage object to use for the compiled container.
DrupalKernel::unserialize public function Overrides Kernel::unserialize
DrupalKernel::updateModules public function Implements Drupal\Core\DrupalKernelInterface::updateModules(). Overrides DrupalKernelInterface::updateModules
DrupalKernel::__construct public function Constructs a DrupalKernel object. Overrides Kernel::__construct
HttpKernelInterface::MASTER_REQUEST constant
HttpKernelInterface::SUB_REQUEST constant
Kernel::$booted protected property
Kernel::$bundleMap protected property
Kernel::$bundles protected property
Kernel::$classes protected property
Kernel::$container protected property
Kernel::$debug protected property
Kernel::$environment protected property
Kernel::$loadClassCache protected property
Kernel::$name protected property 1
Kernel::$rootDir protected property
Kernel::$startTime protected property
Kernel::doLoadClassCache protected function
Kernel::dumpContainer protected function Dumps the service container to PHP code in the cache.
Kernel::EXTRA_VERSION constant
Kernel::getBundle public function @api Overrides KernelInterface::getBundle
Kernel::getBundles public function @api Overrides KernelInterface::getBundles 1
Kernel::getCacheDir public function @api Overrides KernelInterface::getCacheDir
Kernel::getCharset public function @api Overrides KernelInterface::getCharset
Kernel::getContainer public function @api Overrides KernelInterface::getContainer
Kernel::getContainerBaseClass protected function Gets the container's base class.
Kernel::getContainerClass protected function Gets the container class.
Kernel::getContainerLoader protected function Returns a loader for the container.
Kernel::getEnvironment public function @api Overrides KernelInterface::getEnvironment
Kernel::getEnvParameters protected function Gets the environment parameters.
Kernel::getHttpKernel protected function Gets a http kernel from the container
Kernel::getKernelParameters protected function Returns the kernel parameters.
Kernel::getLogDir public function @api Overrides KernelInterface::getLogDir
Kernel::getName public function @api Overrides KernelInterface::getName 1
Kernel::getRootDir public function @api Overrides KernelInterface::getRootDir
Kernel::getStartTime public function @api Overrides KernelInterface::getStartTime
Kernel::handle public function @api Overrides HttpKernelInterface::handle
Kernel::initializeBundles protected function Initializes the data structures related to the bundle management. 1
Kernel::isClassInActiveBundle public function @api Overrides KernelInterface::isClassInActiveBundle
Kernel::isDebug public function @api Overrides KernelInterface::isDebug
Kernel::loadClassCache public function Loads the PHP class cache.
Kernel::locateResource public function Returns the file path for a given resource. Overrides KernelInterface::locateResource
Kernel::MAJOR_VERSION constant
Kernel::MINOR_VERSION constant
Kernel::prepareContainer protected function Prepares the ContainerBuilder before it is compiled.
Kernel::RELEASE_VERSION constant
Kernel::setClassCache public function Used internally.
Kernel::shutdown public function @api Overrides KernelInterface::shutdown
Kernel::stripComments public static function Removes comments from a PHP source string.
Kernel::terminate public function @api Overrides TerminableInterface::terminate
Kernel::VERSION constant
Kernel::VERSION_ID constant
Kernel::__clone public function