使用laravel的redis時候亂用Facades踩了一個坑。。。
創(chuàng)新互聯(lián)公司于2013年成立,先為羅山等服務建站,羅山等地企業(yè),進行企業(yè)商務咨詢服務。為羅山企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務解決您的所有建站問題。
判斷Redis是否有某個key值得時候是可以這樣寫,
Redis::exists(key值)
因為使用了Redis門面,所以可以直接使用Redis::exists而不用先建立實例,就是文檔中介紹的“Facade 基類使用魔術方法 __callStatic() 從你的門面中調(diào)用解析對象”。
簡單說就是沒有exists這個靜態(tài)方法,使用的時候會調(diào)用__callStatic(),建立實例:
$instance = static::getFacadeRoot();
使用Redis時候沒有使用默認庫0,所以按照文檔上的例子指定服務,
代碼如下:
Redis::connection('users'); Redis::exists(key值)
這么做不能判斷key值是否存在,測試以后發(fā)現(xiàn)第二行Redis::exists連接的仍然是默認庫0。
亂用Facades踩到坑了!
我用的是laravel5.2,redis使用Predis。
雖然Redis的Facades是一個靜態(tài)代理,在使用時候"Redis::"也是靜態(tài)唯一的,BUT connection并不是一個靜態(tài)方法。
Redis對應的Facades底層類 Illuminate\Redis\Database,connection方法如下
/** * Get a specific Redis connection instance. * * @param string $name * @return \Predis\ClientInterface|null */ public function connection($name = 'default') { return Arr::get($this->clients, $name ?: 'default'); }
返回redis的鏈接實例。
實際上$this->clients在Redis::調(diào)用__callStatic()建立實例的時候就已經(jīng)初始化,
/** * Create a new Redis connection instance. * * @param array $servers * @return void */ public function __construct(array $servers = []) { $cluster = Arr::pull($servers, 'cluster'); $options = (array) Arr::pull($servers, 'options'); if ($cluster) { $this->clients = $this->createAggregateClient($servers, $options); } else { $this->clients = $this->createSingleClients($servers, $options); } }
打印發(fā)現(xiàn) $this->clients 是將 redis的所有配置都初始化,當connection傳入配置名的時候選擇這個配置鏈接實例。
雖然Redis實例是靜態(tài)的,但是這個redis鏈接并不是。
Redis::exists()更是和connection()方法無關,redis門面調(diào)用__callStatic()后會執(zhí)行 Illuminate\Redis\Database 的exists方法,但是Database沒有這個方法,所以觸發(fā)__call()方法。
/** * Dynamically make a Redis command. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return $this->command($method, $parameters); }
而command() 方法使用的是default配置,也就是說Redis::所有方法除了connection都是默認庫。
/** * Run a command against the Redis database. * * @param string $method * @param array $parameters * @return mixed */ public function command($method, array $parameters = []) { return call_user_func_array([$this->clients['default'], $method], $parameters); }
所以要使用非默認配置的同一個redis鏈接時候必須保存redis實例,
$redis = Redis::connection("user"); $redis->exists(key值);
$redis->exists 不會調(diào)用database的command方法,redis繼續(xù)使用connection選擇的初始化鏈接,不會選擇default配置。
這其實還涉及到Predis底層的實現(xiàn),已經(jīng)超出我的理解范圍。
看完代碼感覺還是有點暈。。。
反正Redis門面還是不要亂用。