PHP LogoPSR-6: Caching Interface (php-fig/cache)

The `php-fig/cache` package provides the official interfaces for PSR-6, the PHP Standard Recommendation for Caching Interface. PSR-6 aims to standardize the way caching libraries are implemented and consumed in PHP applications. By adhering to these interfaces, developers can use any PSR-6 compatible caching library (e.g., Symfony Cache, Doctrine Cache) without changing their application code, making caching implementations interchangeable.

Key interfaces defined in PSR-6 include:

1. `Psr\Cache\CacheItemPoolInterface`: This is the primary interface for interacting with a caching system. It represents a pool of cache items and provides methods to retrieve, save, and delete cache items.
* `getItem(string $key)`: Retrieves a cache item by key. Returns a `CacheItemInterface` instance, which might be a 'hit' (item found) or a 'miss' (item not found).
* `getItems(array $keys = [])`: Retrieves multiple cache items by an array of keys.
* `hasItem(string $key)`: Checks if a cache item exists in the pool.
* `clear()`: Clears all items in the cache pool.
* `deleteItem(string $key)`: Removes a single item from the cache pool.
* `deleteItems(array $keys)`: Removes multiple items from the cache pool.
* `save(CacheItemInterface $item)`: Persists a cache item immediately.
* `saveDeferred(CacheItemInterface $item)`: Queues a cache item for delayed persistence. This allows for batch saving.
* `commit()`: Writes all deferred items to the cache.

2. `Psr\Cache\CacheItemInterface`: Represents a single item stored in the cache. It encapsulates the key, value, and expiration time.
* `getKey()`: Returns the key for the current cache item.
* `get()`: Retrieves the value of the cache item. Returns `null` if the item is a cache 'miss' or has expired.
* `isHit()`: Indicates if the cache item represents a cache 'hit' (i.e., the item exists and is not expired).
* `set($value)`: Sets the value of the cache item.
* `expiresAt(?DateTimeInterface $expiration)`: Sets the absolute expiration time for the item.
* `expiresAfter(int|DateInterval|null $time)`: Sets the relative expiration time for the item.

Advantages of using PSR-6:
* Interoperability: Applications can easily switch between different cache backends (e.g., Redis, Memcached, filesystem) without significant code changes.
* Testability: Decoupling caching logic from concrete implementations makes it easier to test components that rely on caching.
* Maintainability: Promotes cleaner code architecture by defining clear contracts for caching operations.

While `php-fig/cache` only provides interfaces, you would typically install a concrete implementation like `symfony/cache` or `doctrine/cache` which implements these PSR-6 interfaces.

Example Code

```php
<?php

require 'vendor/autoload.php';

use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

/
 * A simple service that demonstrates caching using PSR-6 interface.
 */
class MyDataService
{
    private CacheItemPoolInterface $cache;

    public function __construct(CacheItemPoolInterface $cache)
    {
        $this->cache = $cache;
    }

    /
     * Retrieves data, using cache if available.
     * If data is not in cache, it's fetched and stored for a specified duration.
     */
    public function getData(string $id): string
    {
        $cacheKey = 'my_data_' . $id;
        $item = $this->cache->getItem($cacheKey);

        if ($item->isHit()) {
            echo "Retrieving data for '{$id}' from cache.\n";
            return $item->get();
        }

        echo "Fetching data for '{$id}' from source (not in cache).\n";
        // Simulate a time-consuming operation to fetch data
        sleep(2);
        $data = "Data for item {$id} from the source at " . date('H:i:s');

        // Store the data in cache for 60 seconds
        $item->set($data);
        $item->expiresAfter(60); // 60 seconds expiration

        $this->cache->save($item); // Persist the item

        return $data;
    }

    /
     * Clears a specific item from the cache.
     */
    public function clearDataCache(string $id): void
    {
        $cacheKey = 'my_data_' . $id;
        if ($this->cache->deleteItem($cacheKey)) {
            echo "Cache for '{$id}' cleared successfully.\n";
        } else {
            echo "Failed to clear cache for '{$id}'.\n";
        }
    }

    /
     * Clears all items from the cache pool.
     */
    public function clearAllCache(): void
    {
        if ($this->cache->clear()) {
            echo "All cache items cleared successfully.\n";
        } else {
            echo "Failed to clear all cache items.\n";
        }
    }
}

// --- Example Usage ---

// 1. Set up a PSR-6 compatible cache adapter (e.g., Symfony's FilesystemAdapter)
// This will store cache files in a 'cache' directory in your project root.
$cache = new FilesystemAdapter(
    // a string used as the main cache namespace (deals with collisions)
    $namespace = 'my_app_cache',
    // the default lifetime (in seconds) for cache items that do not define a specific lifetime
    $defaultLifetime = 0,
    // the directory where cache files are stored
    $directory = __DIR__ . '/cache'
);

$service = new MyDataService($cache);

echo "\n--- First Call (should fetch from source) ---\n";
echo $service->getData('item1') . "\n";

echo "\n--- Second Call (should fetch from cache) ---\n";
echo $service->getData('item1') . "\n";

echo "\n--- Third Call for a different item (should fetch from source) ---\n";
echo $service->getData('item2') . "\n";

echo "\n--- Clearing cache for 'item1' ---\n";
$service->clearDataCache('item1');

echo "\n--- Fourth Call (should fetch from source again for 'item1') ---\n";
echo $service->getData('item1') . "\n";

echo "\n--- Clearing all cache ---\n";
$service->clearAllCache();

echo "\n--- Fifth Call (should fetch from source again for 'item2') ---\n";
echo $service->getData('item2') . "\n";

// --- To run this example ---
// 1. Create a `composer.json` file:
/*
{
    "require": {
        "php-fig/cache": "^1.0",
        "symfony/cache": "^5.0 || ^6.0 || ^7.0"
    },
    "autoload": {
        "psr-4": { "": "src/" }
    }
}
*/
// 2. Run `composer install`
// 3. Save the code above as `index.php` (or similar) in your project root.
// 4. Execute `php index.php`

?>
```