class ApcuBackend

Same name in other branches
  1. 9 core/lib/Drupal/Core/Cache/ApcuBackend.php \Drupal\Core\Cache\ApcuBackend
  2. 8.9.x core/lib/Drupal/Core/Cache/ApcuBackend.php \Drupal\Core\Cache\ApcuBackend
  3. 11.x core/lib/Drupal/Core/Cache/ApcuBackend.php \Drupal\Core\Cache\ApcuBackend

Stores cache items in the Alternative PHP Cache User Cache (APCu).

Hierarchy

Expanded class hierarchy of ApcuBackend

1 file declares its use of ApcuBackend
ApcuBackendTest.php in core/tests/Drupal/KernelTests/Core/Cache/ApcuBackendTest.php

File

core/lib/Drupal/Core/Cache/ApcuBackend.php, line 11

Namespace

Drupal\Core\Cache
View source
class ApcuBackend implements CacheBackendInterface {
    
    /**
     * The name of the cache bin to use.
     *
     * @var string
     */
    protected $bin;
    
    /**
     * Prefix for all keys in the storage that belong to this site.
     *
     * @var string
     */
    protected $sitePrefix;
    
    /**
     * Prefix for all keys in this cache bin.
     *
     * Includes the site-specific prefix in $sitePrefix.
     *
     * @var string
     */
    protected $binPrefix;
    
    /**
     * The cache tags checksum provider.
     *
     * @var \Drupal\Core\Cache\CacheTagsChecksumInterface
     */
    protected $checksumProvider;
    
    /**
     * Constructs a new ApcuBackend instance.
     *
     * @param string $bin
     *   The name of the cache bin.
     * @param string $site_prefix
     *   The prefix to use for all keys in the storage that belong to this site.
     * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider
     *   The cache tags checksum provider.
     * @param \Drupal\Component\Datetime\TimeInterface|null $time
     *   The time service.
     */
    public function __construct($bin, $site_prefix, CacheTagsChecksumInterface $checksum_provider, ?TimeInterface $time = NULL) {
        $this->bin = $bin;
        $this->sitePrefix = $site_prefix;
        $this->checksumProvider = $checksum_provider;
        $this->binPrefix = $this->sitePrefix . '::' . $this->bin . '::';
        if (!$time) {
            @trigger_error('Calling ' . __METHOD__ . '() without the $time argument is deprecated in drupal:10.3.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/3387233', E_USER_DEPRECATED);
            $this->time = \Drupal::service(TimeInterface::class);
        }
    }
    
    /**
     * Prepends the APCu user variable prefix for this bin to a cache item ID.
     *
     * @param string $cid
     *   The cache item ID to prefix.
     *
     * @return string
     *   The APCu key for the cache item ID.
     */
    public function getApcuKey($cid) {
        return $this->binPrefix . $cid;
    }
    
    /**
     * {@inheritdoc}
     */
    public function get($cid, $allow_invalid = FALSE) {
        $cache = apcu_fetch($this->getApcuKey($cid));
        return $this->prepareItem($cache, $allow_invalid);
    }
    
    /**
     * {@inheritdoc}
     */
    public function getMultiple(&$cids, $allow_invalid = FALSE) {
        // Translate the requested cache item IDs to APCu keys.
        $map = [];
        foreach ($cids as $cid) {
            $map[$this->getApcuKey($cid)] = $cid;
        }
        $result = apcu_fetch(array_keys($map));
        $cache = [];
        if ($result) {
            foreach ($result as $key => $item) {
                $item = $this->prepareItem($item, $allow_invalid);
                if ($item) {
                    $cache[$map[$key]] = $item;
                }
            }
        }
        unset($result);
        $cids = array_diff($cids, array_keys($cache));
        return $cache;
    }
    
    /**
     * Returns all cached items, optionally limited by a cache ID prefix.
     *
     * APCu is a memory cache, shared across all server processes. To prevent
     * cache item clashes with other applications/installations, every cache item
     * is prefixed with a unique string for this site. Therefore, functions like
     * apcu_clear_cache() cannot be used, and instead, a list of all cache items
     * belonging to this application need to be retrieved through this method
     * instead.
     *
     * @param string $prefix
     *   (optional) A cache ID prefix to limit the result to.
     *
     * @return \APCUIterator
     *   An APCUIterator containing matched items.
     */
    protected function getAll($prefix = '') {
        return $this->getIterator('/^' . preg_quote($this->getApcuKey($prefix), '/') . '/');
    }
    
    /**
     * Prepares a cached item.
     *
     * Checks that the item is either permanent or did not expire.
     *
     * @param object $cache
     *   An item loaded from self::get() or self::getMultiple().
     * @param bool $allow_invalid
     *   If TRUE, a cache item may be returned even if it is expired or has been
     *   invalidated. See ::get().
     *
     * @return mixed
     *   The cache item or FALSE if the item expired.
     */
    protected function prepareItem($cache, $allow_invalid) {
        if (!isset($cache->data)) {
            return FALSE;
        }
        $cache->tags = $cache->tags ? explode(' ', $cache->tags) : [];
        // Check expire time.
        $cache->valid = $cache->expire == Cache::PERMANENT || $cache->expire >= $this->time
            ->getRequestTime();
        // Check if invalidateTags() has been called with any of the entry's tags.
        if (!$this->checksumProvider
            ->isValid($cache->checksum, $cache->tags)) {
            $cache->valid = FALSE;
        }
        if (!$allow_invalid && !$cache->valid) {
            return FALSE;
        }
        return $cache;
    }
    
    /**
     * {@inheritdoc}
     */
    public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANENT, array $tags = []) {
        assert(Inspector::assertAllStrings($tags), 'Cache tags must be strings.');
        $tags = array_unique($tags);
        $cache = new \stdClass();
        $cache->cid = $cid;
        $cache->created = round(microtime(TRUE), 3);
        $cache->expire = $expire;
        $cache->tags = implode(' ', $tags);
        $cache->checksum = $this->checksumProvider
            ->getCurrentChecksum($tags);
        // APCu serializes/unserializes any structure itself.
        $cache->serialized = 0;
        $cache->data = $data;
        // Expiration is handled by our own prepareItem(), not APCu.
        apcu_store($this->getApcuKey($cid), $cache);
    }
    
    /**
     * {@inheritdoc}
     */
    public function setMultiple(array $items = []) {
        foreach ($items as $cid => $item) {
            $this->set($cid, $item['data'], $item['expire'] ?? CacheBackendInterface::CACHE_PERMANENT, $item['tags'] ?? []);
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public function delete($cid) {
        apcu_delete($this->getApcuKey($cid));
    }
    
    /**
     * {@inheritdoc}
     */
    public function deleteMultiple(array $cids) {
        apcu_delete(array_map([
            $this,
            'getApcuKey',
        ], $cids));
    }
    
    /**
     * {@inheritdoc}
     */
    public function deleteAll() {
        apcu_delete($this->getIterator('/^' . preg_quote($this->binPrefix, '/') . '/'));
    }
    
    /**
     * {@inheritdoc}
     */
    public function garbageCollection() {
        // APCu performs garbage collection automatically.
    }
    
    /**
     * {@inheritdoc}
     */
    public function removeBin() {
        apcu_delete($this->getIterator('/^' . preg_quote($this->binPrefix, '/') . '/'));
    }
    
    /**
     * {@inheritdoc}
     */
    public function invalidate($cid) {
        $this->invalidateMultiple([
            $cid,
        ]);
    }
    
    /**
     * {@inheritdoc}
     */
    public function invalidateMultiple(array $cids) {
        foreach ($this->getMultiple($cids) as $cache) {
            $this->set($cache->cid, $cache, $this->time
                ->getRequestTime() - 1);
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public function invalidateAll() {
        foreach ($this->getAll() as $data) {
            $cid = str_replace($this->binPrefix, '', $data['key']);
            $this->set($cid, $data['value'], $this->time
                ->getRequestTime() - 1);
        }
    }
    
    /**
     * Instantiates and returns the APCUIterator class.
     *
     * @param mixed $search
     *   A PCRE regular expression that matches against APC key names, either as a
     *   string for a single regular expression, or as an array of regular
     *   expressions. Or, optionally pass in NULL to skip the search.
     * @param int $format
     *   The desired format, as configured with one or more of the APC_ITER_*
     *   constants.
     * @param int $chunk_size
     *   The chunk size. Must be a value greater than 0. The default value is 100.
     * @param int $list
     *   The type to list. Either pass in APC_LIST_ACTIVE or APC_LIST_DELETED.
     *
     * @return \APCUIterator
     */
    protected function getIterator($search = NULL, $format = APC_ITER_ALL, $chunk_size = 100, $list = APC_LIST_ACTIVE) {
        return new \APCUIterator($search, $format, $chunk_size, $list);
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
ApcuBackend::$bin protected property The name of the cache bin to use.
ApcuBackend::$binPrefix protected property Prefix for all keys in this cache bin.
ApcuBackend::$checksumProvider protected property The cache tags checksum provider.
ApcuBackend::$sitePrefix protected property Prefix for all keys in the storage that belong to this site.
ApcuBackend::delete public function Deletes an item from the cache. Overrides CacheBackendInterface::delete
ApcuBackend::deleteAll public function Deletes all cache items in a bin. Overrides CacheBackendInterface::deleteAll
ApcuBackend::deleteMultiple public function Deletes multiple items from the cache. Overrides CacheBackendInterface::deleteMultiple
ApcuBackend::garbageCollection public function Performs garbage collection on a cache bin. Overrides CacheBackendInterface::garbageCollection
ApcuBackend::get public function Returns data from the persistent cache. Overrides CacheBackendInterface::get
ApcuBackend::getAll protected function Returns all cached items, optionally limited by a cache ID prefix.
ApcuBackend::getApcuKey public function Prepends the APCu user variable prefix for this bin to a cache item ID.
ApcuBackend::getIterator protected function Instantiates and returns the APCUIterator class.
ApcuBackend::getMultiple public function Returns data from the persistent cache when given an array of cache IDs. Overrides CacheBackendInterface::getMultiple
ApcuBackend::invalidate public function Marks a cache item as invalid. Overrides CacheBackendInterface::invalidate
ApcuBackend::invalidateAll public function Marks all cache items as invalid. Overrides CacheBackendInterface::invalidateAll
ApcuBackend::invalidateMultiple public function Marks cache items as invalid. Overrides CacheBackendInterface::invalidateMultiple
ApcuBackend::prepareItem protected function Prepares a cached item.
ApcuBackend::removeBin public function Remove a cache bin. Overrides CacheBackendInterface::removeBin
ApcuBackend::set public function Stores data in the persistent cache. Overrides CacheBackendInterface::set
ApcuBackend::setMultiple public function Store multiple items in the persistent cache. Overrides CacheBackendInterface::setMultiple
ApcuBackend::__construct public function Constructs a new ApcuBackend instance.
CacheBackendInterface::CACHE_PERMANENT constant Indicates that the item should never be removed unless explicitly deleted.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.