phpdotenvについて。

[phpdotenv](https://github.com/vlucas/phpdotenv)について勉強しようと思ったのですが、全体的な説明をしてくださっている記事が見つからなかったので、自力で公式のREAD ME.mdを日本語に訳しました。
前提知識が必要そうなワードは太字にして、参考になりそうな記事のリンクを追記しています。（PHPの[公式マニュアル](https://www.php.net/manual/ja/index.php)は日本語の説明文が難解なのでリンクを張っていませんが、適宜そちらも読みながら理解することをオススメします。）

当方、勉強中の者ですので、不適切な表現がある箇所はバシバシご指摘ください！
（特に、**Loader Customization**の項がほとんど理解できていないため、ご指摘お待ちしております。）

(2019年10月執筆)

# PHP dotenvとは
PHP dotenvは、Ruby言語で使われている **[dotenv](https://github.com/bkeepers/dotenv)** のPHP版です。

`getenv()`メソッドや、`$_ENV`変数、`$_SERVER`変数を使って、`.env`というファイルから**環境変数**を読み込むことができます。

> 参考:[環境変数とは](https://wa3.i-3-i.info/word11027.html)



## Ver.2からの変更点
Ver.3で実装された新機能について説明します。

 - 複数行にわたる変数に対応しました([#301](https://github.com/vlucas/phpdotenv/pull/301))。

 - 環境のどの部分を読み取り及び変更しようとするかの柔軟性が大幅に向上します([#300](https://github.com/vlucas/phpdotenv/pull/300))。
これにより、必要に応じた正しいカスタマイズが可能になります。
 - 新しいネイティブコンストラクターは`Loader`インスタンスを取得するため、今まで`new Dotenv(...)`と記入していた箇所を`Dotenv::create(...)`と書き換える必要があります。）


 - `Loader`インスタンスは値をトリミングしなくなります([#302](https://github.com/vlucas/phpdotenv/pull/302))。
 - `Loader::load()`とその呼び出し元は、ピュアな配列ではなく、値が読み込まれた変数の連想配列を返すようになります([#306](https://github.com/vlucas/phpdotenv/pull/306))。

詳細は、[リリースノート](https://github.com/vlucas/phpdotenv/releases/tag/v3.0.0)と[アップグレードガイド](https://github.com/vlucas/phpdotenv/blob/master/UPGRADING.md)を参照してください。

## なぜ`.env`を使うべきなのか?
データベースや外部サービスの、ユーザー名やパスワード、APIキーなどの機密情報をソースコードに記入しないためです。
環境によって変更する可能性のあるものはすべて、ソースコードの外で環境変数として定義するべきです。
この方法は、モダンなWebアプリが守るべき12の要素(原題:**[Twelve-Factor App](https://12factor.net/ja/)**)でも推奨されています。

> 参考:[Twelve-Factor Appを噛み砕いてみた](https://qiita.com/supreme0110/items/17c58c660137e23ef713)

`.env`ファイルは基本的に、`.htaccess`ファイルや Apache や Nginx のバーチャルホストを変更せずに、アプリケーションに必要なカスタム構成変数を簡単に読み込む事ができます。
プロジェクトの外部でファイルを編集する必要がありません。
プロジェクトの実行方法（Apache、Nginx、CLI、PHP 5.4のビルトインWebサーバーなど）に関係なく、すべての環境変数を共有できます。
環境変数を設定することは、他のどんな方法を採用するよりもずっと簡単だと思われます！

- ApacheやNginxでのバーチャルホストの編集が不要です。
- `php_value`フラグを`.htaccess`ファイルに追加しません。
- 移植や、必要なENV値の共有が簡単に出来ます。
- PHPのビルトインWebサーバーやCLIランナーと互換性があります。

## インストール方法
**Composer**を使用します。

```shell:shell
composer require vlucas/phpdotenv
```

> 参考:[【PHP】Composerは絶対必要!インストール方法と解説で完全攻略
](https://www.sejuku.net/blog/82454)

## 使い方
`.env`ファイルには機密情報を含めるため、特別な理由がなければ、
プロジェクトの`.gitignore`ファイルに`.env`ファイルを追加して
Gitなどのバージョン管理システムで間違ってコミットされる事がないようにしてください。

機密情報ではない環境変数は、一旦`.env.example`という拡張子のファイルを作成して、そこに定義してください。
`.env`ファイルが必要になる人は、各自ローカル環境に`.env.example`ファイルをコピーして、
ファイル名を`.env`に変更してください。
そして、ファイル内で定義してある設定が、ローカル環境で開発をする際に適切な値であることを確認し、
適切じゃない場合は必要に応じて値を変更したり、独自の値を定義したりしてください。

上記の方法をとることで、機密情報がバージョン管理履歴に含まれなくなります。
セキュリティを侵害されるリスクが減り、他のプロジェクトメンバーに機密情報を公開する必要がなくなります。

---

プロジェクトの`root`ディレクトリにある`.env`ファイルに、アプリケーションの構成情報を追加しましょう。

```shell:.env
S3_BUCKET="dotenv"
SECRET_KEY="souper_seekret_key"
```
構成情報を他のメンバーに流用されないよう、`.env`ファイルが`.gitignore`ファイルに追加されていることを確認してください。

`.env.example`と名付けたファイルを作成し、プロジェクトにプッシュします。
このファイルで環境変数を定義しますが、機密情報を公開しないために、値は空白にするか、ダミーの値を入力してください。
変数名は、何についての値なのかが分かるような名前にしましょう。

```shell:.env
S3_BUCKET="devbucket"
SECRET_KEY="abc123"
```

開発中のアプリケーションに`.env`ファイルを読み込みます。

```php:PHP
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
```

`.env`以外のファイル名を使用する場合は、第二引数でファイル名を指定してください。

```php:PHP
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__, 'myconfig');
$dotenv->load();
```

これで、定義されたすべての変数に`getenv()`メソッドを使ってアクセスできるようになり、
`$_ENV`や`$ _SERVER`という**スーパーグローバル変数**の使用が可能になりました。
> 参考:[PHPのスーパーグローバル変数を使う方法【初心者向け】](https://techacademy.jp/magazine/19302)

```php:PHP
$s3_bucket = getenv('S3_BUCKET');
$s3_bucket = $_ENV['S3_BUCKET'];
$s3_bucket = $_SERVER['S3_BUCKET'];
```

開発中のアプリケーションに、Laravelなどのフレームワークを使用している場合は、そのフレームワークに存在する`Request`クラスを使うこともできます。

```php:PHP
$s3_bucket = $request->env('S3_BUCKET');
$s3_bucket = $request->getEnv('S3_BUCKET');
$s3_bucket = $request->server->get('S3_BUCKET');
$s3_bucket = env('S3_BUCKET');
```


### 変数を入れ子にする

環境変数を定義する際、`${…}`という形式で囲うことで定義済の環境変数を引用できます。
これにより、無意味な作業の繰り返しを減らすことができます。

```shell:.env
BASE_DIR="/var/webroot/project-root"
CACHE_DIR="${BASE_DIR}/cache"
TMP_DIR="${BASE_DIR}/tmp"
```

### 不変性

デフォルトの挙動では、**PHP dotenv**が既存の環境変数を上書きすることはありません。
もし既存の環境変数を上書きしたい場合は、`load()`メソッドではなく`overload()`メソッドを使って下さい。

```php:PHP
$dotenv = Dotenv\Dotenv::create(__DIR__);
$dotenv->overload();
```

### `Loader`インスタンスのカスタマイズ

`$_ENV`や`$_SERVER`の変数を使いたくない状況にも、対応可能です！
`Dotenv\Environment\FactoryInterface`のカスタム実装を作成する時に`Dotenv\Loader`に渡すだけです。

それ以前に、デフォルトの実装では、
基礎となる呼び出しをプロキシするための
`Dotenv\Environment\Adapter\AdapterInterface`
の配列を提供できるため、カスタム実装さえ必要ない場合もあります。

たとえば、`$_ENV`と`putenv`だけをいじる場合は、次のようにPHP dotenvをセットアップできます。

```php:PHP
$factory = new Dotenv\Environment\DotenvFactory([
    new Dotenv\Environment\Adapter\EnvConstAdapter(),
    new Dotenv\Environment\Adapter\PutenvAdapter(),
]);

$dotenv = Dotenv\Dotenv::create(__DIR__, null, $factory);
```

## 環境変数の定義を要求する

PHP dotenvを使って、`$_ENV`と`$_SERVER`の変数、もしくは`getenv（）`メソッドに環境変数を定義するよう要求することができます。
（定義されていない場合は、**例外をスロー**します。）
注: `.env`ファイル内の変数の存在チェックはされません。

> 参考: [PHPで例外処理を使う方法を現役エンジニアが解説【初心者向け】
](https://techacademy.jp/magazine/19667)

これがなければアプリが機能しない、という必須の変数を明示したいときに便利です。

下記の特定の文字列を使用します。

```php:PHP
$dotenv->required('DATABASE_DSN');
```

複数指定する場合は、配列を使用します。

```php:PHP
$dotenv->required(['DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASS']);
```

指定した環境変数が定義されていない場合、
PHP dotenvが次のように**定義済みの例外(RuntimeException)** をスローします。

> 参考: [PHPでのエラー処理・例外処理](https://laboradian.com/php-how-to-write-error-and-exception/)

```
One or more environment variables failed assertions: DATABASE_DSN is missing
```

### 空の判定

単に環境変数が定義されているかどうかをチェックするだけではなく、
代入された値が空じゃないかどうかチェックしたい場合は、次のように記入します。

```php:PHP
$dotenv->required('DATABASE_DSN')->notEmpty();
```

すると、環境変数の値が空だった場合に次のような例外が発生します。

```
One or more environment variables failed assertions: DATABASE_DSN is empty
```

### 整数判定

環境変数に代入された値が整数かどうかチェックしたい場合は、次のように記入します。

```php:PHP
$dotenv->required('FOO')->isInteger();
```

整数ではなかった場合、次のような例外が発生します。

```
One or more environment variables failed assertions: FOO is not an integer
```

### 真偽値判定

環境変数に代入された値が真偽値かどうかチェックしたい場合は、次のように記入します。
（真偽値以外にも`"On"`,`"Off"`,`"Yes"`,`"No"`,`"1"`,`"0"`の値も許容します。）

```php:PHP
$dotenv->required('FOO')->isBoolean();
```
真偽値ではなかった場合、次のような例外が発生します。

```
One or more environment variables failed assertions: FOO is not a boolean
```

### 特定の値を指定する

環境変数の値に、任意の固定値を指定することもできます。
使用されるであろうオプションやドライバが多くない場合に役立ちます。

```php:PHP
$dotenv->required('SESSION_STORE')->allowedValues(['Filesystem', 'Memcached']);
```

指定された値に該当しない場合、次のような例外が発生します。

```
One or more environment variables failed assertions: SESSION_STORE is not an
allowed value
```

任意の固定値には、**正規表現**を使用することもできます。

> 参考: [【5分でまるっと理解】PHP正規表現の使い方まとめ](https://eng-entrance.com/php-regularex)

```php:PHP
$dotenv->required('FOO')->allowedRegexValues('([[:lower:]]{3})');
```

### コメントアウト
`.env`ファイル内では、`#`を使用してコメントアウトをする事ができます。

```shell:.env
# this is a comment
VAR="value" # comment
VAR=value # comment
```

## 使用上の注意
新規で開発に参画した方があなたのソースコードを使用する場合、
その方は`.env.example`ファイルの名前を`.env`に変更して、
適切な値を記入する必要があります。

### シェルで環境変数を使用する場合
PHP dotenvを使用するのではなく、シェルの中で`.env`ファイルの環境変数を使用したい場合は、`source`コマンドを使ってください。

```shell
source .env
```

## セキュリティについて

もし、PHP dotenvにセキュリティ上の脆弱性を発見した場合は、
開発者の Graham Campbell にメールを送信してください。
MAIL: graham@alt-three.com

すべての脆弱性に迅速に対処します。

弊社のセキュリティポリシーは、[こちら](https://github.com/vlucas/phpdotenv/security/policy)でご覧いただけます。

## ライセンス

PHP dotenvの権利は、**[三条項BSDライセンス](https://github.com/vlucas/phpdotenv/blob/master/LICENSE)** に基づき主張します。

> 参考:[BSDライセンス](https://ja.wikipedia.org/wiki/BSD%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9)