導語
最近在學習 THinkPHP 5.1,看了 Cache 方法的操作,有一點疑惑。雖然封裝了很多方法,使用的時候很方便,但是對 Redis 的高級操作好像不是很友好,出於學習的目的,對源碼進行了一點小修改。首先聲明兩點:一是此次的修改,只是個人觀點,不適於所有人;二是此次修改僅爲學習所用,各位謹慎修改源碼。
問題
在練習 Redis 的時候,發現如果想要使用高級方法,例如 hSet
、hGet
等,要先返回句柄,然後才能執行。如下
<?php
namespace app\index\controller;
use think\cache\driver\Redis;
use think\Controller;
class RedisTest extends Controller
{
public function index()
{
$redis = new Redis();
$redis = $redis->handler();
dump($redis->hSet('h_name', '1', 'tom'));// int(1)
}
}
可以看到,執行成功。問題是爲什麼要先返回句柄,可以用 __call
這種魔術方法來解決的。
追蹤源碼
既然有了疑惑,就要解惑。追蹤着源碼,看到 thinkphp/library/think/cache/Driver.php
,發現確實沒有 __call
,只是 handler
來返回句柄來執行高級方法。沒想明白爲什麼不用 __clss
。
解決問題
解決方法就是在 thinkphp/library/think/cache/Driver.php
中添加 __call
方法,這樣不止 Redis 可以直接使用高級方法,其他繼承此文件的 Cache 類都可以直接使用。代碼如下
/**
* 執行高級方法
* @param $method
* @param $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return call_user_func_array(array($this->handler(), $method), $parameters);
}
再看下測試代碼
<?php
namespace app\index\controller;
use think\cache\driver\Redis;
use think\Controller;
class RedisTest extends Controller
{
public function index()
{
$redis = new Redis();
// $redis = $redis->handler();
dump($redis->hSet('h_name', '2', 'jerry'));// int(1)
}
}
到此問題已解決。當我修改完的時候,想起 Laravel 似乎就是用的 __call
,然後去看了源碼,確實如此。在 ravel/vendor/laravel/framework/src/Illuminate/Redis/RedisManager.php
中有如下代碼
/**
* Pass methods onto the default Redis connection.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return $this->connection()->{$method}(...$parameters);
}
結語
其實這次小修改的象徵意義大於實際意義,畢竟這不是什麼 bug,使用 handler
也是可以實現的。對我來說更大的意義是,遇到些問題會更傾向於查看源碼。看得多了,自然能力會提升。