跳到內容

快取池與支援的配接器

編輯此頁面

快取池是快取項目的邏輯儲存庫。它們對項目執行所有常見操作,例如儲存或尋找項目。快取池獨立於實際的快取實作。因此,即使底層快取機制從基於檔案系統的快取變更為基於 Redis 或資料庫的快取,應用程式也可以繼續使用相同的快取池。

使用快取合約

CacheInterface 允許僅使用兩個方法和一個回呼來擷取、儲存和刪除快取項目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Contracts\Cache\ItemInterface;

$cache = new FilesystemAdapter();

// The callable will only be executed on a cache miss.
$value = $cache->get('my_cache_key', function (ItemInterface $item): string {
    $item->expiresAfter(3600);

    // ... do some HTTP request or heavy computations
    $computedValue = 'foobar';

    return $computedValue;
});

echo $value; // 'foobar'

// ... and to remove the cache key
$cache->delete('my_cache_key');

開箱即用,使用此介面可提供透過鎖定和提前過期來防止大量請求的保護。提前過期可以透過 get() 方法的第三個 "beta" 參數來控制。請參閱 快取元件 文章以取得更多資訊。

提前過期可以在回呼內透過呼叫 isHit() 方法來偵測:如果這傳回 true,則表示我們目前正在提前在其過期日之前重新計算值。

對於進階用例,回呼可以接受第二個以引用方式傳遞的 bool &$save 引數。透過在回呼內將 $save 設定為 false,您可以指示快取池傳回的值不應儲存在後端。

使用 PSR-6

尋找快取項目

快取池定義了三種方法來尋找快取項目。最常用的方法是 getItem($key),它會傳回由給定鍵識別的快取項目

1
2
3
4
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

$cache = new FilesystemAdapter('app.cache');
$latestNews = $cache->getItem('latest_news');

如果未針對給定鍵定義任何項目,則該方法不會傳回 null 值,而是傳回實作 CacheItem 類別的空物件。

如果您需要同時擷取多個快取項目,請改用 getItems([$key1, $key2, ...]) 方法

1
2
// ...
$stocks = $cache->getItems(['AAPL', 'FB', 'GOOGL', 'MSFT']);

同樣地,如果任何鍵未表示有效的快取項目,您將不會獲得 null 值,而是獲得一個空的 CacheItem 物件。

與擷取快取項目相關的最後一個方法是 hasItem($key),如果存在由給定鍵識別的快取項目,則傳回 true

1
2
// ...
$hasBadges = $cache->hasItem('user_'.$userId.'_badges');

儲存快取項目

儲存快取項目最常用的方法是 Psr\Cache\CacheItemPoolInterface::save,它會立即將項目儲存在快取中(如果項目已儲存,則傳回 true;如果發生某些錯誤,則傳回 false

1
2
3
4
// ...
$userFriends = $cache->getItem('user_'.$userId.'_friends');
$userFriends->set($user->getFriends());
$isSaved = $cache->save($userFriends);

有時,您可能希望不要立即儲存物件,以提高應用程式效能。在這些情況下,請使用 Psr\Cache\CacheItemPoolInterface::saveDeferred 方法將快取項目標記為「準備好要持久化」,然後在您準備好持久化所有項目時呼叫 Psr\Cache\CacheItemPoolInterface::commit 方法

1
2
3
4
5
6
7
8
// ...
$isQueued = $cache->saveDeferred($userFriends);
// ...
$isQueued = $cache->saveDeferred($userPreferences);
// ...
$isQueued = $cache->saveDeferred($userRecentProducts);
// ...
$isSaved = $cache->commit();

當快取項目已成功新增至「持久化佇列」時,saveDeferred() 方法會傳回 true,否則傳回 falsecommit() 方法會在所有擱置項目都成功儲存時傳回 true,否則傳回 false

移除快取項目

快取池包含刪除快取項目、其中一些項目或所有項目的方法。最常見的是 Psr\Cache\CacheItemPoolInterface::deleteItem,它會刪除由給定鍵識別的快取項目(當項目成功刪除或不存在時,它會傳回 true,否則傳回 false

1
2
// ...
$isDeleted = $cache->deleteItem('user_'.$userId);

使用 Psr\Cache\CacheItemPoolInterface::deleteItems 方法同時刪除多個快取項目(僅當所有項目都已刪除時,它才會傳回 true,即使任何或某些項目不存在也是如此)

1
2
// ...
$areDeleted = $cache->deleteItems(['category1', 'category2']);

最後,若要移除儲存在池中的所有快取項目,請使用 Psr\Cache\CacheItemPoolInterface::clear 方法(當所有項目都成功刪除時,該方法會傳回 true

1
2
// ...
$cacheIsEmpty = $cache->clear();

提示

如果在 Symfony 應用程式內部使用快取元件,您可以使用下列指令從快取池中移除項目(這些指令位於 framework bundle 內)

給定池中移除一個特定項目

1
2
3
4
$ php bin/console cache:pool:delete <cache-pool-name> <cache-key-name>

# deletes the "cache_key" item from the "cache.app" pool
$ php bin/console cache:pool:delete cache.app cache_key

您也可以從給定池中移除所有項目

1
2
3
4
5
6
7
$ php bin/console cache:pool:clear <cache-pool-name>

# clears the "cache.app" pool
$ php bin/console cache:pool:clear cache.app

# clears the "cache.validation" and "cache.app" pool
$ php bin/console cache:pool:clear cache.validation cache.app

修剪快取項目

某些快取池不包含自動修剪過期快取項目的機制。例如,FilesystemAdapter 快取在明確要求項目並確定為已過期之前,不會移除過期的快取項目,例如,透過呼叫 Psr\Cache\CacheItemPoolInterface::getItem。在某些工作負載下,這可能會導致陳舊的快取項目持續存在超過其過期時間,從而導致過多、過期的快取項目大量消耗浪費的磁碟或記憶體空間。

此缺點已透過引入 PruneableInterface 解決,它定義了抽象方法 prune()ChainAdapterDoctrineDbalAdapterFilesystemAdapterPdoAdapterPhpFilesAdapter 都實作了這個新介面,允許手動移除陳舊的快取項目

1
2
3
4
5
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

$cache = new FilesystemAdapter('app.cache');
// ... do some set and get operations
$cache->prune();

ChainAdapter 實作本身不直接包含任何修剪邏輯。相反地,當呼叫鏈式配接器的 prune() 方法時,呼叫會委派給其所有相容的快取配接器(而那些未實作 PruneableInterface 的配接器會被靜默忽略)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\PdoAdapter;
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;

$cache = new ChainAdapter([
    new ApcuAdapter(),       // does NOT implement PruneableInterface
    new FilesystemAdapter(), // DOES implement PruneableInterface
    new PdoAdapter(),        // DOES implement PruneableInterface
    new PhpFilesAdapter(),   // DOES implement PruneableInterface
    // ...
]);

// prune will proxy the call to PdoAdapter, FilesystemAdapter and PhpFilesAdapter,
// while silently skipping ApcuAdapter
$cache->prune();

提示

如果在 Symfony 應用程式內部使用快取元件,您可以使用下列指令從所有池中修剪所有項目(這些指令位於 framework bundle 內)

1
$ php bin/console cache:pool:prune
這項作品,包括程式碼範例,已根據 Creative Commons BY-SA 3.0 授權條款授權。
目錄
    版本