diff --git a/core/lib/Drupal/Component/Discovery/YamlDiscovery.php b/core/lib/Drupal/Component/Discovery/YamlDiscovery.php
index 1d147fd..0e042b4 100644
--- a/core/lib/Drupal/Component/Discovery/YamlDiscovery.php
+++ b/core/lib/Drupal/Component/Discovery/YamlDiscovery.php
@@ -8,6 +8,7 @@
 namespace Drupal\Component\Discovery;
 
 use Drupal\Component\Serialization\Yaml;
+use Drupal\Component\FileCache\FileCacheFactory;
 
 /**
  * Provides discovery for YAML files within a given set of directories.
@@ -47,10 +48,27 @@ public function __construct($name, array $directories) {
    */
   public function findAll() {
     $all = array();
-    foreach ($this->findFiles() as $provider => $file) {
-      // If a file is empty or its contents are commented out, return an empty
-      // array instead of NULL for type consistency.
-      $all[$provider] = Yaml::decode(file_get_contents($file)) ?: [];
+
+    $files = $this->findFiles();
+    $provider_by_files = array_flip($files);
+
+    $file_cache = FileCacheFactory::get('yaml_discovery:' . $this->name);
+
+    // Try to load from the file cache first.
+    foreach ($file_cache->getMultiple($files) as $file => $data) {
+      $all[$provider_by_files[$file]] = $data;
+      unset($provider_by_files[$file]);
+    }
+
+    // If there are files left that were not returned from the cache,
+    // load and parse them now. Note the reversed order.
+    if ($provider_by_files) {
+      foreach ($provider_by_files as $file => $provider) {
+        // If a file is empty or its contents are commented out, return an empty
+        // array instead of NULL for type consistency.
+        $all[$provider] = Yaml::decode(file_get_contents($file)) ?: [];
+        $file_cache->set($file, $all[$provider]);
+      }
     }
 
     return $all;
diff --git a/core/lib/Drupal/Component/FileCache/ApcuFileCacheBackend.php b/core/lib/Drupal/Component/FileCache/ApcuFileCacheBackend.php
new file mode 100644
index 0000000..25b6097
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/ApcuFileCacheBackend.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\FileCache\ApcuFileCacheBackend.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * APCu backend for the file cache.
+ */
+class ApcuFileCacheBackend implements FileCacheBackendInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fetch(array $cids) {
+    return apc_fetch($cids);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function store($cid, $data) {
+    apc_store($cid, $data);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    apc_delete($cid);
+  }
+
+}
diff --git a/core/lib/Drupal/Component/FileCache/ChainedFileCacheBackend.php b/core/lib/Drupal/Component/FileCache/ChainedFileCacheBackend.php
new file mode 100644
index 0000000..11f2918
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/ChainedFileCacheBackend.php
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\FileCache\ChainedFileCacheBackend.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Allows to cache data based on file modification dates for various cache
+ * backends.
+ */
+class ChainedFileCacheBackend implements FileCacheBackendInterface {
+
+  /**
+   * The backends to use.
+   *
+   * @var \Drupal\Component\FileCache\FileCacheBackendInterface[]
+   */
+  protected $cacheBackends;
+
+   /**
+    * Constructs a ChainedFileCacheBackend object.
+    *
+    * @param array $configuration
+    *   (optional) The configuration used to configure this class.
+    */
+  public function __construct(array $configuration = []) {
+    foreach ($configuration as $class => $class_config) {
+      if (is_string($class_config)) {
+        $class = $class_config;
+        $class_config = [];
+      }
+      $this->cacheBackends[] = new $class($class_config);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fetch(array $cids) {
+    $return = [];
+    $cid_map = [];
+    foreach ($cids as $cid) {
+      $cid_map[$cid] = $cid;
+    }
+
+    // This does not do validation, because it is unlikely that a cache
+    // earlier in the chain is less current than a later cache.
+    $seen_backends = [];
+
+    foreach ($this->cacheBackends as $cache) {
+      $cached = $cache->fetch(array_values($cid_map));
+      $cid_map = array_diff($cid_map, array_keys($cached));
+      $return += $cached;
+
+      // Write back the fresh data to the seen cache backends.
+      foreach ($seen_backends as $seen_cache) {
+        foreach ($cached as $cid => $data) {
+          $seen_cache->store($cid, $data);
+        }
+      }
+
+      if (empty($cid_map)) {
+        break;
+      }
+      $seen_backends[] = $cache;
+    }
+
+    return $return;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function store($cid, $data) {
+    foreach ($this->cacheBackends as $cache) {
+      $cache->store($cid, $data);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    foreach ($this->cacheBackends as $cache) {
+      $cache->delete($cid);
+    }
+  }
+}
diff --git a/core/lib/Drupal/Component/FileCache/FileCache.php b/core/lib/Drupal/Component/FileCache/FileCache.php
new file mode 100644
index 0000000..9ba59aa
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/FileCache.php
@@ -0,0 +1,152 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\FileCache\FileCache.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Allows to cache data based on file modification dates.
+ */
+class FileCache implements FileCacheInterface {
+
+  /**
+   * Prefix that is used for cache entries.
+   *
+   * The prefix is static, as all file paths are stored with the full path, so
+   * a per-site prefix is not needed.
+   */
+  const CACHE_PREFIX = 'drupal_file_cache';
+
+  /**
+   * Static cache that contains already loaded cache entries.
+   *
+   * This is not an instance variable as all FileCache objects are backed by
+   * the same cache and is useful for e.g. simpletest.
+   *
+   * @var array
+   */
+  protected static $cached = [];
+
+  /**
+   * The collection identifier of this cache.
+   *
+   * @var string
+   */
+  protected $collection;
+
+  /**
+   * The cache backend backing this FileCache object.
+   *
+   * @var \Drupal\Component\FileCache\FileCacheBackendInterface
+   */
+  protected $cache;
+
+  /**
+   * Constructs a FileCache object.
+   *
+   * @param string $collection
+   *   A collection identifier to ensure that the same files could be cached for
+   *   different purposes without clashing.
+   * @param string|null $cache_backend_class
+   *   (optional) The class that should be used as cache backend.
+   * @param array $cache_backend_configuration
+   *   (optional) The configuration for the backend class.
+   */
+  public function __construct($collection, $cache_backend_class = NULL, array $cache_backend_configuration = []) {
+    $this->collection = $collection;
+
+    if (isset($cache_backend_class)) {
+      $this->cache = new $cache_backend_class($cache_backend_configuration);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($filepath) {
+    $filepaths = [$filepath];
+    $cached = $this->getMultiple($filepaths);
+    return isset($cached[$filepath]) ? $cached[$filepath] : NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(array $filepaths) {
+    $file_data = [];
+    $remaining_cids = [];
+
+    // First load from the static cache what we can.
+    foreach ($filepaths as $filepath) {
+      if (!file_exists($filepath)) {
+        continue;
+      }
+
+      $realpath = realpath($filepath);
+      // If the file exists but realpath returns nothing, it is using a stream
+      // wrapper, those are not supported.
+      if (empty($realpath)) {
+        continue;
+      }
+
+      $cid = static::CACHE_PREFIX . ':' . $this->collection . ':' . $realpath;
+      if (isset(static::$cached[$cid]) && static::$cached[$cid]['mtime'] == filemtime($filepath)) {
+        $file_data[$filepath] = static::$cached[$cid]['data'];
+      }
+      else {
+        // Collect a list of cache IDs that we still need to fetch from cache
+        // backend.
+        $remaining_cids[$cid] = $filepath;
+      }
+    }
+
+    // If there are any cache IDs left to fetch from the cache backend.
+    if ($remaining_cids && $this->cache) {
+      $cache_results = $this->cache->fetch(array_keys($remaining_cids)) ?: [];
+      foreach ($cache_results as $cid => $cached) {
+        $filepath = $remaining_cids[$cid];
+        if ($cached['mtime'] == filemtime($filepath)) {
+          $file_data[$cached['filepath']] = $cached['data'];
+          static::$cached[$cid] = $cached;
+        }
+      }
+    }
+
+    return $file_data;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($filepath, $data) {
+    $realpath = realpath($filepath);
+    $cached = [
+      'mtime' => filemtime($filepath),
+      'filepath' => $filepath,
+      'data' => $data,
+    ];
+
+    $cid = static::CACHE_PREFIX . ':' . $this->collection . ':' . $realpath;
+    static::$cached[$cid] = $cached;
+    if ($this->cache) {
+      $this->cache->store($cid, $cached);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($filepath) {
+    $realpath = realpath($filepath);
+    $cid = static::CACHE_PREFIX . ':' . $this->collection . ':' . $realpath;
+
+    unset(static::$cached[$cid]);
+    if ($this->cache) {
+      $this->cache->delete($cid);
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Component/FileCache/FileCacheBackendInterface.php b/core/lib/Drupal/Component/FileCache/FileCacheBackendInterface.php
new file mode 100644
index 0000000..c350802
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/FileCacheBackendInterface.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\FileCache\FileCacheBackendInterface.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Defines an interface inspired by APCu for FileCache backends.
+ */
+interface FileCacheBackendInterface {
+
+  /**
+   * Fetch data from the cache backend.
+   *
+   * @param array $cids
+   *   The cache IDs to fetch.
+   *
+   * @return array
+   *   An array containing cache entries keyed by cache ID.
+   */
+  public function fetch(array $cids);
+
+  /**
+   * Stores data into a cache backend.
+   *
+   * @param string $cid
+   *   The cache ID to store data to.
+   * @param array $data
+   *   The data to store.
+   */
+  public function store($cid, $data);
+
+  /**
+   * Delete data from a cache backend.
+   *
+   * @param string $cid
+   *   The cache ID to delete.
+   */
+  public function delete($cid);
+}
diff --git a/core/lib/Drupal/Component/FileCache/FileCacheFactory.php b/core/lib/Drupal/Component/FileCache/FileCacheFactory.php
new file mode 100644
index 0000000..dd47eb0
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/FileCacheFactory.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Component\FileCache\FileCacheFactory.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Creates a FileCache object.
+ */
+class FileCacheFactory {
+
+  /**
+   * The configuration used to create File Cache objects.
+   *
+   * @var array $configuration
+   */
+  protected static $configuration;
+
+  /**
+   * Instantiates a FileCache object for a given collection identifier.
+   *
+   * @param string $collection
+   *   The collection identifier for this FileCache.
+   * @param array $default_configuration
+   *   (optional) The default configuration for this FileCache identifier. This
+   *   can be used to e.g. specify default usage of a FileCacheCollector class.
+   *
+   * @return \Drupal\Component\FileCache\FileCache
+   *   The initialized FileCache object.
+   */
+  public static function get($collection, $default_configuration = []) {
+    $default_configuration += [
+      'class' => '\Drupal\Component\FileCache\FileCache',
+      'collection' => $collection,
+      'cache_backend_class' => NULL,
+      'cache_backend_configuration' => [],
+    ];
+
+    $configuration = [];
+    if (isset(static::$configuration[$collection])) {
+      $configuration = static::$configuration[$collection];
+    }
+    elseif (isset(static::$configuration['default'])) {
+      $configuration = static::$configuration['default'];
+    }
+
+    // Add defaults to the configuration.
+    $configuration = $configuration + $default_configuration;
+
+    $class = $configuration['class'];
+    return new $class($configuration['collection'], $configuration['cache_backend_class'], $configuration['cache_backend_configuration']);
+  }
+
+  /**
+   * Gets the configuration used for constructing future file cache objects.
+   *
+   * @return array
+   *   The configuration that is used.
+   */
+  public static function getConfiguration() {
+    return static::$configuration;
+  }
+
+  /**
+   * Sets the configuration to use for constructing future file cache objects.
+   *
+   * @param array $configuration
+   *   The configuration to use.
+   */
+  public static function setConfiguration($configuration) {
+    static::$configuration = $configuration;
+  }
+
+}
diff --git a/core/lib/Drupal/Component/FileCache/FileCacheInterface.php b/core/lib/Drupal/Component/FileCache/FileCacheInterface.php
new file mode 100644
index 0000000..27fcd20
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/FileCacheInterface.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\FileCache\FileCacheInterface.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Interface for objects that allow caching file data.
+ */
+interface FileCacheInterface {
+
+  /**
+   * Gets data based on a filename.
+   *
+   * @param string $filepath
+   *   Name of the cache that the cached data is based on.
+   *
+   * @return mixed|null
+   *   The data that was persisted with set() or NULL if there is no data
+   *   or the file has been modified.
+   */
+  public function get($filepath);
+
+  /**
+   * Gets data based on filenames.
+   *
+   * @param string[] $filepaths
+   *   List of file names used as cache identifiers.
+   *
+   * @return array
+   *   List of cached data keyed by the passed in file paths.
+   */
+  public function getMultiple(array $filepaths);
+
+  /**
+   * Store data based on a filename.
+   *
+   * @param string $filepath
+   *   Name of the cache that the cached data is based on.
+   * @param mixed $data
+   *   The data that should be cached.
+   */
+  public function set($filepath, $data);
+
+  /**
+   * Delete data from the cache.
+   *
+   * @param string $filepath
+   *   Name of the cache that the cached data is based on.
+   */
+  public function delete($filepath);
+
+}
diff --git a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php
index 15490b4..593bc1c 100644
--- a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php
+++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php
@@ -48,9 +48,8 @@ class ExtensionInstallStorage extends InstallStorage {
    *   search and to get overrides from.
    */
   public function __construct(StorageInterface $config_storage, $directory = self::CONFIG_INSTALL_DIRECTORY, $collection = StorageInterface::DEFAULT_COLLECTION, $include_profile = TRUE) {
+    parent::__construct($directory, $collection);
     $this->configStorage = $config_storage;
-    $this->directory = $directory;
-    $this->collection = $collection;
     $this->includeProfile = $include_profile;
   }
 
diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php
index de3ac80..91e60a8 100644
--- a/core/lib/Drupal/Core/Config/FileStorage.php
+++ b/core/lib/Drupal/Core/Config/FileStorage.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Serialization\Yaml;
 use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\FileCache\FileCacheFactory;
 
 /**
  * Defines the file storage.
@@ -31,6 +32,13 @@ class FileStorage implements StorageInterface {
   protected $directory = '';
 
   /**
+   * The file cache object.
+   *
+   * @var \Drupal\Component\FileCache\FileCache
+   */
+  protected $fileCache;
+
+  /**
    * Constructs a new FileStorage.
    *
    * @param string $directory
@@ -42,6 +50,7 @@ class FileStorage implements StorageInterface {
   public function __construct($directory, $collection = StorageInterface::DEFAULT_COLLECTION) {
     $this->directory = $directory;
     $this->collection = $collection;
+    $this->fileCache = FileCacheFactory::get('config');
   }
 
   /**
@@ -93,12 +102,18 @@ public function exists($name) {
    * @throws \Drupal\Core\Config\UnsupportedDataTypeConfigException
    */
   public function read($name) {
+    $filename = $this->getFilePath($name);
+    if ($data = $this->fileCache->get($filename)) {
+      return $data;
+    }
+
     if (!$this->exists($name)) {
       return FALSE;
     }
-    $data = file_get_contents($this->getFilePath($name));
+    $data = file_get_contents($filename);
     try {
       $data = $this->decode($data);
+      $this->fileCache->set($filename, $data);
     }
     catch (InvalidDataTypeException $e) {
       throw new UnsupportedDataTypeConfigException(SafeMarkup::format('Invalid data type in config @name: !message', array(
@@ -127,7 +142,7 @@ public function readMultiple(array $names) {
    */
   public function write($name, array $data) {
     try {
-      $data = $this->encode($data);
+      $encoded_data = $this->encode($data);
     }
     catch (InvalidDataTypeException $e) {
       throw new StorageException(SafeMarkup::format('Invalid data type in config @name: !message', array(
@@ -137,11 +152,11 @@ public function write($name, array $data) {
     }
 
     $target = $this->getFilePath($name);
-    $status = @file_put_contents($target, $data);
+    $status = @file_put_contents($target, $encoded_data);
     if ($status === FALSE) {
       // Try to make sure the directory exists and try writing again.
       $this->ensureStorage();
-      $status = @file_put_contents($target, $data);
+      $status = @file_put_contents($target, $encoded_data);
     }
     if ($status === FALSE) {
       throw new StorageException('Failed to write configuration file: ' . $this->getFilePath($name));
@@ -149,6 +164,9 @@ public function write($name, array $data) {
     else {
       drupal_chmod($target);
     }
+
+    $this->fileCache->set($target, $data);
+
     return TRUE;
   }
 
@@ -163,6 +181,7 @@ public function delete($name) {
       }
       return FALSE;
     }
+    $this->fileCache->delete($this->getFilePath($name));
     return drupal_unlink($this->getFilePath($name));
   }
 
@@ -174,6 +193,8 @@ public function rename($name, $new_name) {
     if ($status === FALSE) {
       throw new StorageException('Failed to rename configuration file from: ' . $this->getFilePath($name) . ' to: ' . $this->getFilePath($new_name));
     }
+    $this->fileCache->delete($this->getFilePath($name));
+    $this->fileCache->delete($this->getFilePath($new_name));
     return TRUE;
   }
 
diff --git a/core/lib/Drupal/Core/Config/InstallStorage.php b/core/lib/Drupal/Core/Config/InstallStorage.php
index 06618d7..977c4c7 100644
--- a/core/lib/Drupal/Core/Config/InstallStorage.php
+++ b/core/lib/Drupal/Core/Config/InstallStorage.php
@@ -62,8 +62,7 @@ class InstallStorage extends FileStorage {
    *   default collection.
    */
   public function __construct($directory = self::CONFIG_INSTALL_DIRECTORY, $collection = StorageInterface::DEFAULT_COLLECTION) {
-    $this->directory = $directory;
-    $this->collection = $collection;
+    parent::__construct($directory, $collection);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php
index d4ae53e..1a13165 100644
--- a/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php
+++ b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\DependencyInjection;
 
+use Drupal\Component\FileCache\FileCacheFactory;
 use Drupal\Component\Serialization\Yaml;
 use Symfony\Component\DependencyInjection\Alias;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -34,30 +35,22 @@ class YamlFileLoader
 {
 
     /**
-     * Statically cached yaml files.
-     *
-     * Especially during tests, YAML files are re-parsed often.
-     *
-     * @var array
+     * @param \Drupal\Core\DependencyInjection\ContainerBuilder $container
      */
-    static protected $yaml = array();
+    protected $container;
 
     /**
-     * @param \Drupal\Core\DependencyInjection\ContainerBuilder $container
+     * File cache object.
+     *
+     * @var \Drupal\Component\FileCache\FileCache
      */
-    protected $container;
+    protected $fileCache;
+
 
     public function __construct(ContainerBuilder $container)
     {
       $this->container = $container;
-    }
-
-    /**
-     * Resets the internal cache. This method is mostly useful for tests.
-     */
-    public static function reset()
-    {
-        static::$yaml = array();
+      $this->fileCache = FileCacheFactory::get('container_yaml_loader');
     }
 
     /**
@@ -67,10 +60,14 @@ public static function reset()
      */
     public function load($file)
     {
-        if (!isset(static::$yaml[$file])) {
-          static::$yaml[$file] = $this->loadFile($file);
+        // Load from the file cache, fall back to loading the file.
+        // @todo Refactor this to cache parsed definition objects in
+        // https://www.drupal.org/node/2464053
+        $content = $this->fileCache->get($file);
+        if (!$content) {
+          $content = $this->loadFile($file);
+          $this->fileCache->set($file, $content);
         }
-        $content = static::$yaml[$file];
 
         // Not supported.
         //$this->container->addResource(new FileResource($path));
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index be9821d..0daf8ae 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core;
 
+use Drupal\Component\FileCache\FileCacheFactory;
 use Drupal\Component\ProxyBuilder\ProxyDumper;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\Timer;
@@ -245,6 +246,26 @@ public static function createFromRequest(Request $request, $class_loader, $envir
       $response->prepare($request)->send();
     }
 
+    // Initialize the FileCacheFactory component. We have to do it here instead
+    // of in \Drupal\Component\FileCache\FileCacheFactory because we can not use
+    // the Settings object in a component.
+    $configuration = Settings::get('file_cache');
+
+    // Provide a default configuration, if not set.
+    if (!isset($configuration['default'])) {
+      $configuration['default'] = [
+        'class' => '\Drupal\Component\FileCache\FileCache',
+        'cache_backend_class' => NULL,
+        'cache_backend_configuration' => [],
+      ];
+      // @todo Use extension_loaded('apcu') for non-testbot
+      //  https://www.drupal.org/node/2447753.
+      if (function_exists('apc_fetch')) {
+        $configuration['default']['cache_backend_class'] = '\Drupal\Component\FileCache\ApcuFileCacheBackend';
+      }
+    }
+    FileCacheFactory::setConfiguration($configuration);
+
     return $kernel;
   }
 
diff --git a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
index 4681977..13348c2 100644
--- a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
+++ b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Extension;
 
+use Drupal\Component\FileCache\FileCacheFactory;
 use Drupal\Core\Extension\Discovery\RecursiveExtensionFilterIterator;
 use Drupal\Core\Site\Settings;
 
@@ -81,6 +82,13 @@ class ExtensionDiscovery {
   protected $root;
 
   /**
+   * The file cache object.
+   *
+   * @var \Drupal\Component\FileCache\FileCache
+   */
+  protected $fileCache;
+
+  /**
    * Constructs a new ExtensionDiscovery object.
    *
    * @param string $root
@@ -88,6 +96,7 @@ class ExtensionDiscovery {
    */
   public function __construct($root) {
     $this->root = $root;
+    $this->fileCache = FileCacheFactory::get('extension_discovery');
   }
 
   /**
@@ -406,6 +415,12 @@ protected function scanDirectory($dir, $include_tests) {
       if (!preg_match(static::PHP_FUNCTION_PATTERN, $fileinfo->getBasename('.info.yml'))) {
         continue;
       }
+
+      if ($cached_extension = $this->fileCache->get($fileinfo->getPathName())) {
+        $files[$cached_extension->getType()][$key] = $cached_extension;
+        continue;
+      }
+
       // Determine extension type from info file.
       $type = FALSE;
       $file = $fileinfo->openFile('r');
@@ -441,6 +456,7 @@ protected function scanDirectory($dir, $include_tests) {
       $extension->origin = $dir;
 
       $files[$type][$key] = $extension;
+      $this->fileCache->set($fileinfo->getPathName(), $extension);
     }
     return $files;
   }
diff --git a/core/lib/Drupal/Core/FileCache/PhpStorageFileCacheBackend.php b/core/lib/Drupal/Core/FileCache/PhpStorageFileCacheBackend.php
new file mode 100644
index 0000000..5424c61
--- /dev/null
+++ b/core/lib/Drupal/Core/FileCache/PhpStorageFileCacheBackend.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\FileCache\PhpStorageFileCache.
+ */
+
+namespace Drupal\Core\FileCache;
+
+use Drupal\Component\FileCache\FileCacheBackendInterface;
+use Drupal\Core\PhpStorage\PhpStorageFactory;
+
+/**
+ * Allows to cache data based on file modification dates in PhpStorage.
+ */
+class PhpStorageFileCacheBackend implements FileCacheBackendInterface {
+
+  /**
+   * PHP code storage object to use for the files.
+   *
+   * @var \Drupal\Component\PhpStorage\PhpStorageInterface
+   */
+  protected $storage;
+
+  /**
+   * Constructs a PHP Storage FileCache backend.
+   *
+   * @param array $configuration
+   *   (optional) Configuration used to configure this object.
+   */
+  public function __construct($configuration) {
+    $name = isset($configuration['name']) ? $configuration['name'] : 'file_cache';
+    $this->storage = PhpStorageFactory::get($name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fetch(array $cids) {
+    $cached = [];
+
+    foreach ($cids as $cid) {
+      $cid_hash = basename($cid) . '-' . md5($cid) . '.php';
+      if ($file = $this->storage->getFullPath($cid_hash)) {
+        $data = @include $file;
+        if ($data !== FALSE) {
+          $cached[$cid] = $data;
+        }
+      }
+    }
+
+    return $cached;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function store($cid, $data) {
+    $cid_hash = basename($cid) . '-' . md5($cid) . '.php';
+    $content = '<?php return unserialize(' . var_export(serialize($data), TRUE) . ');';
+    $this->storage->save($cid_hash, $content);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    $cid_hash = basename($cid) . '-' . md5($cid) . '.php';
+    $this->storage->delete($cid_hash);
+  }
+
+}
diff --git a/core/modules/config/src/Tests/ConfigImportUITest.php b/core/modules/config/src/Tests/ConfigImportUITest.php
index ba44925..63fec56 100644
--- a/core/modules/config/src/Tests/ConfigImportUITest.php
+++ b/core/modules/config/src/Tests/ConfigImportUITest.php
@@ -55,6 +55,10 @@ function testImport() {
 
     // Create updated configuration object.
     $new_site_name = 'Config import test ' . $this->randomString();
+    // Accessing the configuration import UI might have cached the files in the
+    // APC user cache. Wait a second so we can be sure that they get a different
+    // file modification time.
+    sleep(1);
     $this->prepareSiteNameUpdate($new_site_name);
     $this->assertIdentical($staging->exists($name), TRUE, $name . ' found.');
 
diff --git a/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php b/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php
index 53998e7..cb6ebc5 100644
--- a/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php
+++ b/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php
@@ -95,6 +95,11 @@ public function testImportDeleteUninstall() {
     // synchronization is correct.
     $this->assertText('This synchronization will delete data from the field entity_test.field_tel.');
 
+    // Accessing the configuration import UI might have cached the files in the
+    // file cache. Wait a second so we can be sure that they get a different
+    // file modification time.
+    sleep(2);
+
     // Stage an uninstall of the text module to test the message for multiple
     // fields.
     unset($core_extension['module']['text']);
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 1ae8e58..9ab799b 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\simpletest;
 
+use Drupal\Component\FileCache\FileCacheFactory;
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Serialization\Yaml;
 use Drupal\Component\Utility\Crypt;
@@ -1071,8 +1072,9 @@ protected function setContainerParameter($name, $value) {
     $services['parameters'][$name] = $value;
     file_put_contents($filename, Yaml::encode($services));
 
-    // Clear the YML file cache.
-    YamlFileLoader::reset();
+    // Ensure that the cache is deleted for the yaml file loader.
+    $file_cache = FileCacheFactory::get('container_yaml_loader');
+    $file_cache->delete($filename);
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Component/FileCache/ChainedFileCacheBackendTest.php b/core/tests/Drupal/Tests/Component/FileCache/ChainedFileCacheBackendTest.php
new file mode 100644
index 0000000..0875cb8
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/ChainedFileCacheBackendTest.php
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\FileCache\ChainedFileCacheBackendTest.
+ */
+
+namespace Drupal\Tests\Component\FileCache;
+
+use Drupal\Component\FileCache\ChainedFileCacheBackend;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Component\FileCache\ChainedFileCacheBackend
+ * @group FileCache
+ */
+class ChainedFileCacheBackendTest extends UnitTestCase {
+
+  /**
+   * The chained file cache backend class.
+   *
+   * @var \Drupal\Component\FileCache\FileCacheBackendInterface
+   */
+   protected $cache;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $configuration = [
+      '\Drupal\Tests\Component\FileCache\StaticFileCacheBackend',
+      '\Drupal\Tests\Component\FileCache\StaticFileCacheBackend' => [
+        'bin' => 'preseeded_cache',
+      ],
+    ];
+
+    $this->cache = new ChainedFileCacheBackend($configuration);
+  }
+
+  /**
+   * @covers ::__construct
+   * @covers ::fetch
+   */
+  public function testFetch() {
+    $backend_outer = $this->getMockBuilder('\Drupal\Component\FileCache\FileCacheBackendInterface')
+      ->setMethods(['fetch', 'store', 'delete'])
+      ->getMock();
+    $backend_outer->expects($this->once())
+      ->method('store')
+      ->with($this->equalTo('foo'), $this->equalTo(42));
+
+    $backend_outer->expects($this->once())
+      ->method('fetch')
+      ->with($this->equalTo(['foo', 'bar', 'not_found']))
+      ->willReturn(['bar' => 23]);
+
+    $backend_inner = $this->getMockBuilder('\Drupal\Component\FileCache\FileCacheBackendInterface')
+      ->setMethods(['fetch', 'store', 'delete'])
+      ->getMock();
+    $backend_inner->expects($this->once())
+      ->method('fetch')
+      ->with($this->equalTo(['foo', 'not_found']))
+      ->willReturn(['foo' => 42]);
+
+    $backend_third = $this->getMockBuilder('\Drupal\Component\FileCache\FileCacheBackendInterface')
+      ->setMethods(['fetch', 'store', 'delete'])
+      ->getMock();
+    $backend_third->expects($this->once())
+      ->method('fetch')
+      ->with($this->equalTo(['not_found']))
+      ->willReturn([]);
+
+    $this->setCacheBackends([$backend_outer, $backend_inner, $backend_third]);
+
+    $result = $this->cache->fetch(['foo', 'bar', 'not_found']);
+    $this->assertEquals(['foo' => 42, 'bar' => 23], $result);
+  }
+
+  /**
+   * @covers ::fetch
+   */
+  public function testFetchEmpty() {
+    $backend_outer = $this->getMockBuilder('\Drupal\Component\FileCache\FileCacheBackendInterface')
+      ->setMethods(['fetch', 'store', 'delete'])
+      ->getMock();
+
+    $backend_outer->expects($this->once())
+      ->method('fetch')
+      ->with($this->equalTo(['foo']))
+      ->willReturn(['foo' => 42]);
+
+    $backend_inner = $this->getMockBuilder('\Drupal\Component\FileCache\FileCacheBackendInterface')
+      ->setMethods(['fetch', 'store', 'delete'])
+      ->getMock();
+    $backend_inner->expects($this->never())
+      ->method('fetch');
+
+    $this->setCacheBackends([$backend_outer, $backend_inner]);
+
+    $result = $this->cache->fetch(['foo']);
+    $this->assertEquals(['foo' => 42], $result);
+  }
+
+  /**
+   * @covers ::store
+   */
+  public function testStore() {
+    $backend_outer = $this->getMockBuilder('\Drupal\Component\FileCache\FileCacheBackendInterface')
+      ->setMethods(['fetch', 'store', 'delete'])
+      ->getMock();
+    $backend_outer->expects($this->once())
+      ->method('store')
+      ->with($this->equalTo('foo'), $this->equalTo(42));
+
+    $backend_inner = $this->getMockBuilder('\Drupal\Component\FileCache\FileCacheBackendInterface')
+      ->setMethods(['fetch', 'store', 'delete'])
+      ->getMock();
+    $backend_inner->expects($this->once())
+      ->method('store')
+      ->with($this->equalTo('foo'), $this->equalTo(42));
+
+    $this->setCacheBackends([$backend_outer, $backend_inner]);
+    $this->cache->store('foo', 42);
+  }
+
+  /**
+   * @covers ::delete
+   */
+  public function testDelete() {
+    $backend_outer = $this->getMockBuilder('\Drupal\Component\FileCache\FileCacheBackendInterface')
+      ->setMethods(['fetch', 'store', 'delete'])
+      ->getMock();
+    $backend_outer->expects($this->once())
+      ->method('delete')
+      ->with($this->equalTo('foo'));
+
+    $backend_inner = $this->getMockBuilder('\Drupal\Component\FileCache\FileCacheBackendInterface')
+      ->setMethods(['fetch', 'store', 'delete'])
+      ->getMock();
+    $backend_inner->expects($this->once())
+      ->method('delete')
+      ->with($this->equalTo('foo'));
+
+    $this->setCacheBackends([$backend_outer, $backend_inner]);
+    $this->cache->delete('foo');
+  }
+
+  /**
+   * Sets the protected cacheBackends value of the chained cache backend.
+   *
+   * @param \Drupal\Component\FileCache\FileCacheBackendInterface[] $backends
+   *   The backends to set on the class.
+   */
+  protected function setCacheBackends($backends) {
+    $reflection = new \ReflectionClass($this->cache);
+    $reflection_property = $reflection->getProperty('cacheBackends');
+    $reflection_property->setAccessible(TRUE);
+    $reflection_property->setValue($this->cache, $backends);
+  }
+}
diff --git a/core/tests/Drupal/Tests/Component/FileCache/FileCacheFactoryTest.php b/core/tests/Drupal/Tests/Component/FileCache/FileCacheFactoryTest.php
new file mode 100644
index 0000000..3e8103f
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/FileCacheFactoryTest.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\FileCache\FileCacheFactoryTest.
+ */
+
+namespace Drupal\Tests\Component\FileCache;
+
+use Drupal\Component\FileCache\FileCacheFactory;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Component\FileCache\FileCacheFactory
+ * @group FileCache
+ */
+class FileCacheFactoryTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $settings = [
+      'collection' => 'test-23',
+      'cache_backend_class' => '\Drupal\Tests\Component\FileCache\StaticFileCacheBackend',
+      'cache_backend_configuration' => [
+        'bin' => 'dog',
+      ],
+    ];
+    $configuration = FileCacheFactory::getConfiguration();
+    if (!$configuration) {
+      $configuration = [];
+    }
+    $configuration += [ 'test_foo_settings' => $settings ];
+    FileCacheFactory::setConfiguration($configuration);
+  }
+
+  /**
+   * @covers ::get
+   */
+  public function testGet() {
+    $file_cache = FileCacheFactory::get('test_foo_settings', []);
+
+    // Ensure the right backend and configuration is used.
+    $filename = __DIR__ . '/Fixtures/llama-23.txt';
+    $realpath = realpath($filename);
+    $cid = 'drupal_file_cache:test-23:' . $realpath;
+
+    $file_cache->set($filename, 23);
+
+    $static_cache = new StaticFileCacheBackend(['bin' => 'dog']);
+    $result = $static_cache->fetch([$cid]);
+    $this->assertNotEmpty($result);
+
+    // Cleanup static caches.
+    $file_cache->delete($filename);
+  }
+
+  /**
+   * @covers ::setConfiguration
+   */
+  public function testSetConfiguration() {
+    $configuration = FileCacheFactory::getConfiguration();
+    $configuration['test_foo_bar'] = ['bar' => 'llama'];
+    FileCacheFactory::setConfiguration($configuration);
+  }
+
+  /**
+   * @covers ::getConfiguration
+   *
+   * @depends testSetConfiguration
+   */
+  public function testGetConfiguration() {
+    $configuration = FileCacheFactory::getConfiguration();
+    $this->assertEquals(['bar' => 'llama'], $configuration['test_foo_bar']);
+  }
+}
diff --git a/core/tests/Drupal/Tests/Component/FileCache/FileCacheTest.php b/core/tests/Drupal/Tests/Component/FileCache/FileCacheTest.php
new file mode 100644
index 0000000..fda714d
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/FileCacheTest.php
@@ -0,0 +1,147 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\FileCache\FileCacheTest.
+ */
+
+namespace Drupal\Tests\Component\FileCache;
+
+use Drupal\Component\FileCache\FileCache;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Component\FileCache\FileCache
+ * @group FileCache
+ */
+class FileCacheTest extends UnitTestCase {
+
+  /**
+   * FileCache object used for the tests.
+   *
+   * @var \Drupal\Component\FileCache\FileCache
+   */
+  protected $fileCache;
+
+  /**
+   * Static FileCache object used for verification of tests.
+   *
+   * @var \Drupal\Component\FileCache\FileCacheBackendInterface
+   */
+  protected $staticFileCache;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->fileCache = new FileCache('test', '\Drupal\Tests\Component\FileCache\StaticFileCacheBackend', ['bin' => 'llama']);
+    $this->staticFileCache = new StaticFileCacheBackend(['bin' => 'llama']);
+  }
+
+  /**
+   * @covers ::get
+   * @covers ::__construct
+   */
+  public function testGet() {
+    // Test a cache miss.
+    $result = $this->fileCache->get(__DIR__ . '/Fixtures/no-llama-42.yml');
+    $this->assertNull($result);
+
+    // Test a cache hit.
+    $filename = __DIR__ . '/Fixtures/llama-42.txt';
+    $realpath = realpath($filename);
+    $cid = 'drupal_file_cache:test:' . $realpath;
+    $data = [
+      'mtime' => filemtime($realpath),
+      'filepath' => $realpath,
+      'data' => 42,
+    ];
+
+    $this->staticFileCache->store($cid, $data);
+
+    $result = $this->fileCache->get($filename);
+    $this->assertEquals(42, $result);
+
+    // Cleanup static caches.
+    $this->fileCache->delete($filename);
+  }
+
+  /**
+   * @covers ::getMultiple
+   */
+  public function testGetMultiple() {
+    // Test a cache miss.
+    $result = $this->fileCache->getMultiple([__DIR__ . '/Fixtures/no-llama-42.yml']);
+    $this->assertEmpty($result);
+
+    // Test a cache hit.
+    $filename = __DIR__ . '/Fixtures/llama-42.txt';
+    $realpath = realpath($filename);
+    $cid = 'drupal_file_cache:test:' . $realpath;
+    $data = [
+      'mtime' => filemtime($realpath),
+      'filepath' => $realpath,
+      'data' => 42,
+    ];
+
+    $this->staticFileCache->store($cid, $data);
+
+    $result = $this->fileCache->getMultiple([$filename]);
+    $this->assertEquals([$filename => 42], $result);
+
+    // Test a static cache hit.
+    $file2 = __DIR__ . '/Fixtures/llama-23.txt';
+    $this->fileCache->set($file2, 23);
+
+    $result = $this->fileCache->getMultiple([$filename, $file2]);
+    $this->assertEquals([$filename => 42, $file2 => 23], $result);
+
+    // Cleanup static caches.
+    $this->fileCache->delete($filename);
+    $this->fileCache->delete($file2);
+  }
+
+  /**
+   * @covers ::set
+   */
+  public function testSet() {
+    $filename = __DIR__ . '/Fixtures/llama-23.txt';
+    $realpath = realpath($filename);
+    $cid = 'drupal_file_cache:test:' . $realpath;
+    $data = [
+      'mtime' => filemtime($realpath),
+      'filepath' => $realpath,
+      'data' => 23,
+    ];
+
+    $this->fileCache->set($filename, 23);
+    $result = $this->staticFileCache->fetch([$cid]);
+    $this->assertEquals([$cid => $data], $result);
+
+    // Cleanup static caches.
+    $this->fileCache->delete($filename);
+  }
+
+  /**
+   * @covers ::delete
+   */
+  public function testDelete() {
+    $filename = __DIR__ . '/Fixtures/llama-23.txt';
+    $realpath = realpath($filename);
+    $cid = 'drupal_file_cache:test:' . $realpath;
+
+    $this->fileCache->set($filename, 23);
+
+    // Ensure data is removed after deletion.
+    $this->fileCache->delete($filename);
+
+    $result = $this->staticFileCache->fetch([$cid]);
+    $this->assertEquals([], $result);
+
+    $result = $this->fileCache->get($filename);
+    $this->assertNull($result);
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-23.txt b/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-23.txt
new file mode 100644
index 0000000..4099407
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-23.txt
@@ -0,0 +1 @@
+23
diff --git a/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-42.txt b/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-42.txt
new file mode 100644
index 0000000..d81cc07
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-42.txt
@@ -0,0 +1 @@
+42
diff --git a/core/tests/Drupal/Tests/Component/FileCache/StaticFileCacheBackend.php b/core/tests/Drupal/Tests/Component/FileCache/StaticFileCacheBackend.php
new file mode 100644
index 0000000..ed82b81
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/StaticFileCacheBackend.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\FileCache\StaticFileCacheBackend.
+ */
+
+namespace Drupal\Tests\Component\FileCache;
+
+use Drupal\Component\FileCache\FileCacheBackendInterface;
+
+/**
+ * Allows to cache data based on file modification dates in a static cache.
+ */
+class StaticFileCacheBackend implements FileCacheBackendInterface {
+
+  /**
+   * Internal static cache.
+   *
+   * @var array
+   */
+  protected static $cache = [];
+
+  /**
+   * Bin used for storing the data in the static cache.
+   *
+   * @var string
+   */
+  protected $bin;
+
+  /**
+   * Constructs a PHP Storage FileCache backend.
+   *
+   * @param array $configuration
+   *   (optional) Configuration used to configure this object.
+   */
+  public function __construct($configuration) {
+    $this->bin = isset($configuration['bin']) ? $configuration['bin'] : 'file_cache';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fetch(array $cids) {
+    $result = [];
+    foreach ($cids as $cid) {
+      if (isset(static::$cache[$this->bin][$cid])) {
+        $result[$cid] = static::$cache[$this->bin][$cid];
+      }
+    }
+
+    return $result;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function store($cid, $data) {
+    static::$cache[$this->bin][$cid] = $data;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    unset(static::$cache[$this->bin][$cid]);
+  }
+
+  /**
+   * Allows tests to reset the static cache to avoid side effects.
+   */
+  public static function reset() {
+    static::$cache = [];
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/FileCache/Fixtures/42.php.txt b/core/tests/Drupal/Tests/Core/FileCache/Fixtures/42.php.txt
new file mode 100644
index 0000000..8c7eb97
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/FileCache/Fixtures/42.php.txt
@@ -0,0 +1 @@
+<?php return unserialize('i:42;');
diff --git a/core/tests/Drupal/Tests/Core/FileCache/PhpStorageFileCacheBackendTest.php b/core/tests/Drupal/Tests/Core/FileCache/PhpStorageFileCacheBackendTest.php
new file mode 100644
index 0000000..5da2fd2
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/FileCache/PhpStorageFileCacheBackendTest.php
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\FileCache\PhpStorageFileCacheBackendTest.
+ */
+
+namespace Drupal\Tests\Core\FileCache;
+
+use Drupal\Core\FileCache\PhpStorageFileCacheBackend;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\FileCache\PhpStorageFileCacheBackend
+ * @group FileCache
+ */
+class PhpStorageFileCacheBackendTest extends UnitTestCase {
+
+  /**
+   * The PhpStorage file cache backend class.
+   *
+   * @var \Drupal\Core\FileCache\FileCacheBackendInterface
+   */
+   protected $cache;
+
+  /**
+   * PHP code storage mock object to use for the files.
+   *
+   * @var \Drupal\Component\PhpStorage\PhpStorageInterface
+   */
+  protected $storageMock;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->cache = $this->getMockBuilder('\Drupal\Core\FileCache\PhpStorageFileCacheBackend')
+      ->disableOriginalConstructor()
+      ->setMethods(null)
+      ->getMock();
+
+    $this->storageMock = $this->getMockBuilder('\Drupal\Component\PhpStorage\PhpStorageInterface')
+      ->setMethods(['getFullPath', 'save', 'delete', 'exists', 'load', 'writeable', 'deleteAll', 'listAll'])
+      ->getMock();
+
+    // Set the storageMock for the cache.
+    $reflection = new \ReflectionClass($this->cache);
+    $reflection_property = $reflection->getProperty('storage');
+    $reflection_property->setAccessible(TRUE);
+    $reflection_property->setValue($this->cache, $this->storageMock);
+  }
+
+  /**
+   * @covers ::__construct
+   * @covers ::fetch
+   */
+  public function testFetch() {
+    $cid = 'foo/bar.txt';
+    $cid_hash = basename($cid) . '-' . md5($cid) . '.php';
+
+    $this->storageMock->expects($this->once())
+      ->method('getFullPath')
+      ->with($this->equalTo($cid_hash))
+      ->willReturn(__DIR__ . '/Fixtures/42.php.txt');
+
+    $result = $this->cache->fetch([$cid]);
+    $this->assertEquals([$cid => 42], $result);
+  }
+
+  /**
+   * @covers ::store
+   */
+  public function testStore() {
+    $cid = 'foo/bar.txt';
+    $cid_hash = basename($cid) . '-' . md5($cid) . '.php';
+
+    $this->storageMock->expects($this->once())
+      ->method('save')
+      ->with($this->equalTo($cid_hash), $this->equalTo('<?php return unserialize(\'i:42;\');'));
+
+    $this->cache->store($cid, 42);
+  }
+
+  /**
+   * @covers ::delete
+   */
+  public function testDelete() {
+    $cid = 'foo/bar.txt';
+    $cid_hash = basename($cid) . '-' . md5($cid) . '.php';
+
+    $this->storageMock->expects($this->once())
+      ->method('delete')
+      ->with($this->equalTo($cid_hash));
+
+    $this->cache->delete($cid);
+  }
+}
