Heim > Backend-Entwicklung > PHP-Tutorial > PSR-Caching-Schnittstelle in PHP

PSR-Caching-Schnittstelle in PHP

DDD
Freigeben: 2025-01-11 16:05:43
Original
978 Leute haben es durchsucht

PSR-Caching Interface in PHP

Hallo zusammen!

Läuft Ihre Anwendung aufgrund wiederholter Datenbankabfragen langsam? Oder haben Sie Probleme beim Wechsel zwischen verschiedenen Caching-Bibliotheken? Tauchen wir ein in PSR-6, den Standard, der Caching in PHP vorhersehbar und austauschbar macht!

Dieser Artikel ist Teil der PHP PSR-Standardserie. Wenn Sie neu sind, ist es eine gute Idee, mit den PSR-1-Grundlagen zu beginnen.

Welches Problem löst PSR-6? (2 Minuten)

Vor PSR-6 hatte jede Cache-Bibliothek ihre eigene einzigartige Arbeitsweise. Möchten Sie von Memcached zu Redis wechseln? Schreiben Sie Ihren Code neu. Von einem Framework auf ein anderes migrieren? Lernen Sie die neue Caching-API kennen. PSR-6 löst dieses Problem, indem es eine gemeinsame Schnittstelle bereitstellt, die alle Cache-Bibliotheken implementieren können.

Kernschnittstelle (5 Minuten)

Werfen wir einen Blick auf die beiden Hauptakteure:

1. CacheItemPoolInterface

Dies ist Ihr Cache-Manager. Stellen Sie es sich als ein Lager vor, in dem Sie Artikel lagern und abrufen können:

<code class="language-php"><?php namespace Psr\Cache;

interface CacheItemPoolInterface
{
    public function getItem($key);
    public function getItems(array $keys = array());
    public function hasItem($key);
    public function clear();
    public function deleteItem($key);
    public function deleteItems(array $keys);
    public function save(CacheItemInterface $item);
    public function saveDeferred(CacheItemInterface $item);
    public function commit();
}

?></code>
Nach dem Login kopieren

2. CacheItemInterface

Dies stellt ein einzelnes Element im Cache dar:

<code class="language-php"><?php namespace Psr\Cache;

interface CacheItemInterface
{
    public function getKey();
    public function get();
    public function isHit();
    public function set($value);
    public function expiresAt($expiration);
    public function expiresAfter($time);
}

?></code>
Nach dem Login kopieren

Praktische Anwendung (10 Minuten)

Hier ist ein praktisches Beispiel aus unserer Codebasis:

1. Cache-Element-Implementierung

<code class="language-php"><?php namespace JonesRussell\PhpFigGuide\PSR6;

use Psr\Cache\CacheItemInterface;
use DateTimeInterface;
use DateInterval;
use DateTime;

class CacheItem implements CacheItemInterface
{
    private $key;
    private $value;
    private $isHit;
    private $expiration;

    public function __construct(string $key)
    {
        $this->key = $key;
        $this->isHit = false;
    }

    public function getKey(): string
    {
        return $this->key;
    }

    public function get()
    {
        return $this->value;
    }

    public function isHit(): bool
    {
        return $this->isHit;
    }

    public function set($value): self
    {
        $this->value = $value;
        return $this;
    }

    public function expiresAt(?DateTimeInterface $expiration): self
    {
        $this->expiration = $expiration;
        return $this;
    }

    public function expiresAfter($time): self
    {
        if ($time instanceof DateInterval) {
            $this->expiration = (new DateTime())->add($time);
        } elseif (is_int($time)) {
            $this->expiration = (new DateTime())->add(new DateInterval("PT{$time}S"));
        } else {
            $this->expiration = null;
        }
        return $this;
    }

    // Helper method for our implementation
    public function getExpiration(): ?DateTimeInterface
    {
        return $this->expiration;
    }

    // Helper method for our implementation
    public function setIsHit(bool $hit): void
    {
        $this->isHit = $hit;
    }
}</code>
Nach dem Login kopieren

2. Cache-Pool-Implementierung

<code class="language-php"><?php namespace JonesRussell\PhpFigGuide\PSR6;

use Psr\Cache\CacheItemPoolInterface;
use Psr\Cache\CacheItemInterface;
use RuntimeException;

class FileCachePool implements CacheItemPoolInterface
{
    private $directory;
    private $deferred = [];

    public function __construct(string $directory)
    {
        if (!is_dir($directory) && !mkdir($directory, 0777, true)) {
            throw new RuntimeException("Cannot create cache directory: {$directory}");
        }
        $this->directory = $directory;
    }

    public function getItem($key): CacheItemInterface
    {
        $this->validateKey($key);

        if (isset($this->deferred[$key])) {
            return $this->deferred[$key];
        }

        $item = new CacheItem($key);
        $path = $this->getPath($key);

        if (file_exists($path)) {
            try {
                $data = unserialize(file_get_contents($path));
                if (!$data['expiration'] || $data['expiration'] > new DateTime()) {
                    $item->set($data['value']);
                    $item->setIsHit(true);
                    return $item;
                }
                unlink($path);
            } catch (\Exception $e) {
                // Log error and continue with cache miss
            }
        }

        return $item;
    }

    public function getItems(array $keys = []): iterable
    {
        $items = [];
        foreach ($keys as $key) {
            $items[$key] = $this->getItem($key);
        }
        return $items;
    }

    public function hasItem($key): bool
    {
        return $this->getItem($key)->isHit();
    }

    public function clear(): bool
    {
        $this->deferred = [];
        $files = glob($this->directory . '/*.cache');

        if ($files === false) {
            return false;
        }

        $success = true;
        foreach ($files as $file) {
            if (!unlink($file)) {
                $success = false;
            }
        }
        return $success;
    }

    public function deleteItem($key): bool
    {
        $this->validateKey($key);
        unset($this->deferred[$key]);

        $path = $this->getPath($key);
        if (file_exists($path)) {
            return unlink($path);
        }
        return true;
    }

    public function deleteItems(array $keys): bool
    {
        $success = true;
        foreach ($keys as $key) {
            if (!$this->deleteItem($key)) {
                $success = false;
            }
        }
        return $success;
    }

    public function save(CacheItemInterface $item): bool
    {
        $path = $this->getPath($item->getKey());
        $data = [
            'value' => $item->get(),
            'expiration' => $item->getExpiration()
        ];

        try {
            if (file_put_contents($path, serialize($data)) === false) {
                return false;
            }
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    public function saveDeferred(CacheItemInterface $item): bool
    {
        $this->deferred[$item->getKey()] = $item;
        return true;
    }

    public function commit(): bool
    {
        $success = true;
        foreach ($this->deferred as $item) {
            if (!$this->save($item)) {
                $success = false;
            }
        }
        $this->deferred = [];
        return $success;
    }

    private function getPath(string $key): string
    {
        return $this->directory . '/' . sha1($key) . '.cache';
    }

    private function validateKey(string $key): void
    {
        if (!is_string($key) || preg_match('#[{}()/@:\\]#', $key)) {
            throw new InvalidArgumentException(
                'Invalid key: ' . var_export($key, true)
            );
        }
    }
}</code>
Nach dem Login kopieren

Praktische Anwendung (5 Minuten)

Sehen wir uns an, wie man es in echtem Code verwendet:

<code class="language-php">// 基本用法
$pool = new FileCachePool('/path/to/cache');

try {
    // 存储值
    $item = $pool->getItem('user.1');
    if (!$item->isHit()) {
        $userData = $database->fetchUser(1); // 您的数据库调用
        $item->set($userData)
             ->expiresAfter(3600); // 1 小时
        $pool->save($item);
    }
    $user = $item->get();
} catch (\Exception $e) {
    // 优雅地处理错误
    log_error('缓存操作失败:' . $e->getMessage());
    $user = $database->fetchUser(1); // 回退到数据库
}</code>
Nach dem Login kopieren

Allgemeine Fallen (3 Minuten)

  1. Schlüsselüberprüfung
  2. Fehlerbehandlung

Was kommt als nächstes?

Morgen besprechen wir PSR-7 (HTTP Message Interface). Wenn Sie an einfacherem Caching interessiert sind, lesen Sie unseren kommenden Artikel zu PSR-16 (Simple Caching), der eine einfachere Alternative zu PSR-6 bietet.

Ressourcen

  • Offizielle PSR-6-Spezifikation
  • Unsere Beispielcodebasis (v0.6.0 – PSR-6-Implementierung)
  • Symfony-Caching-Komponente
  • PHP-Cache

Das obige ist der detaillierte Inhalt vonPSR-Caching-Schnittstelle in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage