Redisのデータベース番号を".env"に持たせた際にハマった件について(Laravel)
これからLaravelが依存関係で利用している"vlucas/phpdotenv"でハマります。
自分の同じようハマった人へ、少しでも手助けとなりますように。
《想定読者》
- Laravelを使っている/今後使いたい人で、先人の失敗談に興味のある人。
- LaravelでRedisを利用する際、DB番号0が無いと怒られたことのある人。
- Laravelを構成するライブラリのソースコードを読む習慣のない人。(読みましょう)
《背景》
いきなり外部のリンクで恐縮ですが、
これを参考にしながらRedisへの接続を設定していた。
その中で以下の箇所がありますが、
'redis' => [
'client' => 'predis',
'default' => [
'host' => env('REDIS_HOST', 'localhost'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
],
"database"も.envに持たせた方が扱いやすいこともあり、以下のように内容を書き換えた。
'redis' => [
'client' => 'predis',
'default' => [
'host' => env('REDIS_HOST'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT'),
'database' => env('REDIS_DB'),
],
],
合わせて.envに次の定義を行った。
REDIS_HOST=localhost
REDIS_PASSWORD=hoge
REDIS_PORT=6379
REDIS_DB=0
Redisへの接続を試行すると失敗した。
RedisからそんなDBはないと怒られてしまっているのだが、0番DBはRedis上に存在している。
《究明》
.envの書き方を変えつつ、artisan tinker で env('REDIS_DB') を実行してみた。
- 「REDIS_DB=0」の場合
>>> ""
結果: 空 - 「REDIS_DB=1」の場合
>>> "1"
結果: 文字列の1 - 「REDIS_DB="1"」の場合
>>> "1"
結果: 文字列の1 - 「REDIS_DB="0"」の場合
>>> "0"
結果: 文字列の0
もしかして、数字の0で定義をすると、空文字に変換されているのでは…。
実際に"0"で定義することで、Redisへの接続時に発生していた問題が解決した。
《原因》
.envの書き方に問題があるらしい。
…というよりも、Laravelが利用している"vlucas/phpdotenv"ライブラリの問題ともいえる。
(少しバージョンが異なるが)実際のソースコードは以下。
同じ事象に遭遇し、issueを上げている人がいました。
見たところLaravelが依存関係と使用しているdotenvライブラリのバージョンが古いという理由で、issueは未解決のままクローズされてました。
原因の箇所はvlucas/phpdotenv/src/Dotenv.phpの180行目付近です。
バグか仕様かはわかりませんが、以下の挙動となります。
protected static function sanitiseVariableValue($value)
{
$value = trim($value); // ここで$value = "0" と評価される。
if (!$value) { // この行で false と評価される。
return ''; // 最終的に "0" ではなく "" に代わりreturnされる。
}
if (strpbrk($value[0], '"\'') !== false) { // value starts with a quote
...
同ライブラリの最新版についてはどうなっているかを確認したところ…。
全く同じコードのままでした。
vlucas/phpdotenvライブラリを利用する場合、.envファイルの内容によっては意図しない動作となることがあるため、十分にご注意を…。
《対策》
- env関数で.envの内容を読み込む際は、可能であればデフォルト値を設定する。
- .env を利用する際は、〇〇=0という書き方はしないようにする。
- 困ったらLaravelや依存ライブラリのソースコードを読むようにする。
以上です。
今回も閲覧いただきありがとうございました。