LaravelのRedisで存在しないキーを取得しようとするとnullが返ってくるお話
false
が返ってきたり null
が返ってきたりする楽しい世界です。
前提
動作環境
- Laradock
- Laravel 6.12
- Redis 5.0.3
- phpredis 5.1.1
DBの中身
- Laravel 6.12
- Redis 5.0.3
- phpredis 5.1.1
Redis の中には key1
のみが入っているとします。
127.0.0.1:6379> SET key1 value1
OK
127.0.0.1:6379> KEYS *
1) "key1"
要約
Redis
Redis で存在しないキーを指定すると、 nil
が返ってきます。
127.0.0.1:6379> GET key1
"value1"
127.0.0.1:6379> GET key2
(nil)
PhpRedis
PhpRedis では、boolean 型の false
が返ってきます。
$redis = new Redis();
$redis->connect('redis', 6379);
$value = $redis->get('key2');
var_dump($value);
string(6) "value1"
bool(false)
Laravel
Laravel で Redis に接続するときに PhpRedis を使っている場合、null 型の null
が返ってきます。
use Illuminate\Support\Facades\Redis;
Redis::set('key1', 'value1');
$value = Redis::get('key1'); //--> "value1"
$value = Redis::get('key2'); //--> null
解説
Redis
Redis の GET
や MGET
で存在しないキーを取得しようとすると、 nil
が返ってきます。
"nil"
という 文字列 を SET
することはできますが、 nil
という 特別な値 を SET
することはできません。1
127.0.0.1:6379> GET key2
(nil)
127.0.0.1:6379> SET key3 nil
OK
127.0.0.1:6379> GET key3
"nil"
PhpRedis
PhpRedis の get
や mget
で存在しないキーを取得しようとすると、 boolean 型の false
が返ってきます。
このことは 公式ドキュメント にも明記されています。
Return value
String or Bool: If key didn't exist, FALSE is returned. Otherwise, the value related to this key is returned.
しかし、ここでぜひ思い出していただきたいのは、PHP では "0"
や空文字と false
は等しく扱われるということです。
// 値として "0" をセットしてみる。
$redis->set('key4', 0);
$val4 = $redis->get('key4');
// キーの存在チェックのつもり...
if (!$val4) {
echo "key4は存在しない";
}
// 値として空文字をセットしてみる。
$redis->set('key5', "");
$val5 = $redis->get('key5');
// これもキーの存在チェックのつもり...
if (!$val5) {
echo "key5は存在しない";
}
さて、結果はどうでしょうか?
key4は存在しない
key5は存在しない
これを防ぐには、 ===
演算子による厳密比較しかありません。
// 正しいキーの存在チェック
if ($val4 === false) {
echo "key4は存在しない";
}
Laravel
さて、ようやく本題です。
Laravel では、Redis にアクセスする際に PhpRedis
を使うことができます。
PhpRedis
を使っているのですから、 get()
や mget()
も false
を返してきそうなものですが、実際には null
が返ってきます。
その理由は Illuminate\Redis\Connections\PhpRedisConnection.php
にあります。
public function get($key)
{
$result = $this->command('get', [$key]);
return $result !== false ? $result : null;
}
public function mget(array $keys)
{
return array_map(function ($value) {
return $value !== false ? $value : null;
}, $this->command('mget', [$keys]));
}
取得した値が false
かどうかをわざわざチェックして、 false
だったときには null
を返すようにしていることが分かります。
なぜこんな面倒なことをしているのか?
かつて PhpRedis が返す false
をそのまま使った結果、キャッシュ周りで バグ が起きました。そのときに null
を返すようにしたようです。
感想
Laravel で Redis にアクセスするときに PhpRedis を使っているからといって、PhpRedis と同じ結果になるとは限りません。
バグ修正時の ある開発者のコメント をもじって言うならば、
僕らは Laravel を使っているのであって、PhpRedis を直接使っているわけではない
といったところでしょうか。2
参考
- Laravel 公式ドキュメント
- PHP 公式ドキュメント
- PhpRedis
- Why does GET/MGET return false instead of null for non-existent keys?
- 同様の違和感を感じる人は多いみたいですが、破壊的変更になるため却下されたようです。
- Why does GET/MGET return false instead of null for non-existent keys?
- 同様の違和感を感じる人は多いみたいですが、破壊的変更になるため却下されたようです。
Author And Source
この問題について(LaravelのRedisで存在しないキーを取得しようとするとnullが返ってくるお話), 我々は、より多くの情報をここで見つけました https://qiita.com/aminevsky/items/40c431e0ee714c28a101著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .