PHP+Redis快取技術一覽
點選進入“PHP開源社群”
免費獲取進階面試、文件、影片資源
有否想過PHP使用
redis
作為快取時,如何能:
1.前後臺模組共用Model層;
2. 但是,不能每個Model類都進行快取,這樣太浪費Redis資源;
3. 前後臺模組可以自由決定從資料庫還是從快取讀資料;
4. 沒有冗餘程式碼;
5. 使用方便。
這裡我們先展示實現的最終效果。
最終的程式碼和使用說明請移步Github:
http://github.com/yeszao/php-redis-cache
馬上安裝使用命令:
$ composer install yeszao/cache
經過簡單配置就可以使用,請參看Github的README說明。
1、最終效果
假設在MVC框架中,
model
層有一個
Book
類和一個
getById
方法,如下:
class Book
{
public function getById($id)
{
return $id;
}
}
加入快取技術之後,原來方法的 呼叫方式 和 返回的資料結構 都不應該改變。
所以,我們希望,最後的效果應該是這樣的:
(new Book)->getById(100); // 原始的、不用快取的呼叫方式,還是原來的方式,一般是讀取資料庫的資料。
(new Book)->getByIdCache(100); // 使用快取的呼叫方式,快取鍵名為:app_models_book:getbyid: + md5(引數列表)
(new Book)->getByIdClear(100); // 刪除這個快取
(new Book)->getByIdFlush(); // 刪除 getById() 方法對應的所有快取,即刪除 app_models_book:getbyid:*。這個方法不需要引數。
這樣我們可以很清楚的明白自己在做什麼,同時又知道資料的來源函式,並且被引用方式完全統一,可謂一箭三雕。
其實實現起來也比較簡單,就是使用PHP的魔術方法 __call() 方法。
2、__call()方法
這裡簡單說明一下
__call
方法的作用。
在PHP中,當我們訪問一個不存在的類方法時,就會呼叫這個類的
__call()
方法。
(如果類方法不存在,又沒有寫
__call()
方法,PHP會直接報錯)
假設我們有一個
Book
類:
class Book
{
public function __call($name, $arguments)
{
echo '類Book不存在方法', $name, PHP_EOL;
}
public function getById($id)
{
echo '我的ID是', $id, PHP_EOL;
}
}
當呼叫
存在的
getName(50)
方法時,程式列印:
我的ID是50
。
而如果呼叫
不存在的
getAge()
方法時,程式就會執行到A類的
__call()
方法裡面,這裡會列印:
類Book不存在方法getAge
。
這就是
__call
的原理。
3、實現細節
接下來我們就利用
__call()
方法的這種特性,來實現快取策略。
從上面的例子,我們看到,
__call()
方法被呼叫時,會傳入兩個引數。
-
$name
:想要呼叫的方法名 -
$arguments
:引數列表
我們就可以在引數上面做文章。
還是以
Book
類為例,我們假設其原本結構如下:
class Book
{
public function __call($name, $arguments)
{
// 待填充內容
}
public function getById($id)
{
return ['id' => $id, 'title' => 'PHP快取技術' . $id];
}
}
開始之前,我們還確認Redis的連線,這是快取必須用到的,這裡我們寫個簡單的單例類:
class Common
{
private static $redis = null;
public static function redis()
{
if (self::$redis === null) {
self::$redis = new \Redis('127.0.0.1');
self::$redis->connect('redis');
}
return self::$redis;
}
然後,我們開始填充
__call()
方法程式碼,具體說明請看註釋:
class Book
{
public function __call($name, $arguments)
{
// 因為我們主要是根據方法名的字尾決定具體操作,
// 所以如果傳入的 $name 長度小於5,可以直接報錯
if (strlen($name) < 5) {
exit('Method does not exist.');
}
// 接著,我們擷取 $name,獲取原方法和要執行的動作,
// 是cache、clear還是flush,這裡我們取了個巧,動作
// 的名稱都是5個字元,這樣擷取就非常高效。
$method = substr($name, 0, -5);
$action = substr($name, -5);
// 當前呼叫的類名稱,包括名稱空間的名稱
$class = get_class();
// 生成快取鍵名,$arguments稍後再加上
$key = sprintf('%s:%s:', str_replace('\\', '_', $class), $method);
// 都用小寫好看點
$key = strtolower($key);
switch ($action) {
case 'Cache':
// 快取鍵名加上$arguments
$key = $key . md5(json_encode($arguments));
// 從Redis中讀取資料
$data = Common::redis()->get($key);
// 如果Redis中有資料
if ($data !== false) {
$decodeData = json_decode($data, JSON_UNESCAPED_UNICODE);
// 如果不是JSON格式的資料,直接返回,否則返回json解析後的資料
return $decodeData === null ? $data : $decodeData;
}
// 如果Redis中沒有資料則繼續往下執行
// 如果原方法不存在
if (method_exists($this, $method) === false) {
exit('Method does not exist.');
}
// 呼叫原方法獲取資料
$data = call_user_func_array([$this, $method], $arguments);
// 儲存資料到Redis中以便下次使用
Common::redis()->set($key, json_encode($data), 3600);
// 結束執行並返回資料
return $data;
break;
case 'Clear':
// 快取鍵名加上$arguments
$key = $key . md5(json_encode($arguments));
return Common::redis()->del($key);
break;
case 'Flush':
$key = $key . '*';
// 獲取所有符合 $class:$method:* 規則的快取鍵名
$keys = Common::redis()->keys($key);
return Common::redis()->del($keys);
break;
default:
exit('Method does not exist.');
}
}
// 其他方法
}
這樣就實現了我們開始時的效果。
4、實際使用時
在實際使用中,我們需要做一些改變,把這一段程式碼歸入一個類中,
然後在model層的基類中引用這個類,再傳入Redis控制代碼、類物件、方法名和引數,
這樣可以降低程式碼的耦合,使用起來也更靈活。
*宣告:本文於網路整理,版權歸原作者所有,如來源資訊有誤或侵犯權益,請聯絡我們刪除或授權事宜。
END
PHP開源社群
掃描關注 進入”PHP資料“
免費獲取進階
面試、文件、影片資源
點選“檢視原文”獲取更多
- 用“最好的語言”PHP,做一個機器學習資料集
- PHP開發中,如何做錯誤與異常處理呢 ?
- phper如何用Rust開發PHP擴充套件Liunx版【詳細教程】
- PHP 使用 CURL 詳解
- 小程式如何使用訂閱訊息(PHP程式碼 小程式js程式碼)
- MySQL提高效能,緩解資料庫壓力,你會做讀寫分離嗎?
- 深入理解 glibc malloc:記憶體分配器實現原理
- Laravel 成為最佳 PHP 框架的 14 個理由!
- 7 款顏值 yyds 的 Linux 作業系統 !
- 一文了解“最好程式語言”PHP 必知的 16 個程式設計法則!
- 終於有人把 "單點" 登入說清楚了!
- PHP程式執行Python指令碼(接收資料及傳參)
- 服務端 TCP 連線 TIME_WAIT 怎麼破?
- Shell 分析日誌檔案命令全面總結!
- 有些PHP程式設計師,不知道如何有效的除錯BUG
- 10個你可能不曾用過卻很有用的 Linux 命令
- PHP如何解決百萬級全站使用者訊息推送問題
- PHP Redis快取技術一覽
- Seata-php 入門與下半年展望
- 3 個PHP 知識總結:Memcache、快取和正則