快取池與支援的配接器
快取池是快取項目的邏輯儲存庫。它們對項目執行所有常見操作,例如儲存或尋找項目。快取池獨立於實際的快取實作。因此,即使底層快取機制從基於檔案系統的快取變更為基於 Redis 或資料庫的快取,應用程式也可以繼續使用相同的快取池。
建立快取池
快取池是透過快取配接器建立的,快取配接器是實作 CacheInterface 和 Psr\Cache\CacheItemPoolInterface
的類別。此元件提供了多個配接器,可在您的應用程式中使用。
使用快取合約
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
,否則傳回 false
。commit()
方法會在所有擱置項目都成功儲存時傳回 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()。ChainAdapter、DoctrineDbalAdapter 和 FilesystemAdapter、PdoAdapter 和 PhpFilesAdapter 都實作了這個新介面,允許手動移除陳舊的快取項目
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