11
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Laravelの.envには特別扱いされる文字列があった

Last updated at Posted at 2018-04-02

まとめ

Laravelの.envではいくつかの文字列が特別扱いされて文字列ではない値に自動的に変換されます。機能としては前からあったようですが、公式ドキュメントにその記述が追加されたのは2018年3月末のこのコミットの模様。2018年4月2日現在では日本語版には反映されていません。

.envの記述 env()ヘルパーの値
true (bool) true
(true) (bool) true
false (bool) false
(false) (bool) false
empty (string) ''
(empty) (string) ''
null (null) null
(null) (null) null

ついでにこれら特別扱いされる文字列を変換させずにそのまま文字列として値が取れるように書きたければ、たとえば'true'なら以下のように書く必要があります。1

FOO="\"true\""

経緯

その値がboolであるような設定値を用意したいと思いました。仮にその名前を'app.my_flag', .envの中では'MY_FLAG'と書くつもりだったとします。プログラム中ではconfig('app.my_flag')でその値にアクセスできる感じ。

最初はこうしました。

.envに追加:

MY_FLAG=false

config/app.phpに追加:

    'my_flag' => \App\MyHelper::env_bool('MY_FLAG'),

\App\MyHelper::env_boolは自作のヘルパー関数です。

    public static function env_bool($key, $default = false)
    {
        $result = env($key);

        if (is_null($result)) {
            return $default;
        }

        if ($result === 'true') {
            return true;
        }

        if ($result === 'false') {
            return false;
        }

        throw new \Exception(sprintf('invalid bool: key=%s, value=%s', $key, var_export($result, true)));
    }

とりあえず動作確認でtinkerコマンドを打つといきなりエラーです。

% php artisan tinker

In MyHelper.php line 21:

  invalid bool: key=MY_FLAG, value=true


ありゃー、なんでenv()がはじめからtrue返すんだと思ってソース追っかけたら、こんな風になってたわけですよ。

if (! function_exists('env')) {
    /**
     * Gets the value of an environment variable.
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    function env($key, $default = null)
    {
        $value = getenv($key);

        if ($value === false) {
            return value($default);
        }

        switch (strtolower($value)) {
            case 'true':
            case '(true)':
                return true;
            case 'false':
            case '(false)':
                return false;
            case 'empty':
            case '(empty)':
                return '';
            case 'null':
            case '(null)':
                return;
        }

        if (strlen($value) > 1 && Str::startsWith($value, '"') && Str::endsWith($value, '"')) {
            return substr($value, 1, -1);
        }

        return $value;
    }
}

知らんかったーと思ってヘルパー関数のマニュアルを確認したら初めに書いた記述にいきつきました。env_boolなんてはじめから書く必要はなかったのです。しかしよくよく調べたらドキュメントの更新はつい3日前なのでこんなの知るわけがないですわな。間が悪いw

で””で囲まれてたらはがす処理もあるようなのでtrueって文字列を書きたいときはとりあえず""で囲めばいいんじゃないかなという当たりを付けて、

.envに追加:

MY_STRING="true"

config/app.phpに追加:

    'my_string' => env('MY_STRING'),

と準備して試してみましたがだめでした。

% php artisan tinker
Psy Shell v0.8.17 (PHP 7.2.4 — cli) by Justin Hileman
>>> config('app.my_string')
=> true
>>>

よくよくソースを読むと以下のような事情でした。

  • envヘルパーはgetenv()で取った値の文字列が""で囲まれていたら、両端の""を削ります。(上記のとおり)

  • .envファイルを読みこんで環境変数に設定する役割はphpdotenvパッケージの仕事ですが、これは""で囲まれた文字列は""をはがします。文字列に「"」を含めたければ「\」でエスケープする必要があります。

ということで""を剥がすひとがもう一人いたわけですね。

MY_STRING="\"true\""

とすることで、めでたくちゃんと取れるようになりました。

% php artisan tinker
Psy Shell v0.8.17 (PHP 7.2.4 — cli) by Justin Hileman
>>> config('app.my_string')
=> "true"
>>>
  1. 余談ですが、両端に「"」をもつ文字列を値としたいときは、FOO="\"\"foo\"\""のようにする必要があります。

11
9
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?