homebrewでPHP+XDebug+VSCodeの開発環境構築をやり直す

Laravelの`artisan serve`で起動したビルトインサーバーでデバッグをします。以前、PHPとXDebugを入れていたのですが、うまく動かなかったので再挑戦。
結果、PHPを入れ直すことになったのでその手順を残しておきます。

* macOS High Sierra
* PHP 7.1.20
* Visual Studio Code

## 使えるようになるまでの手順
### homebrewでPHP
以前homebrewでPHPを入れていたはずだったのですが、`which`してみるとなぜかMacのデフォルトのphpを向いていることに気づきました。
調べてみると、`Homebrew/php`がdeprecatedされた影響とのこと。

* [【Homebrew】PHPの設定に注意！〜Homebrew/phpの廃止〜](https://qiita.com/33yuki/items/8621a476533767ccb1c4)
* [homebrewでphp71-*系がインストールできなくなってた](http://rskull.hateblo.jp/entry/2018/04/06/164236)

の記事を参考に、過去の設定を削除し、phpを入れ直します。

```bash
# 設定の削除
# 必要に応じてバックアップを取ってください
$ rm /usr/local/etc/php/7.1/conf.d/*

# brewからインストールしたPHP関連のモジュールをすべて削除
$ brew untap homebrew/php
$ brew list | grep php
php71
php71-xdebug
php@7.1
$ brew uninstall --force php71 php71-xdebug php@7.1

# 再インストール
$ brew install php@7.1
$ brew link --force php@7.1
```

以下のような表示が出た場合、

```
If you need to have this software first in your PATH instead consider running:
  echo 'export PATH="/usr/local/opt/php@7.1/bin:$PATH"' >> ~/.bash_profile
  echo 'export PATH="/usr/local/opt/php@7.1/sbin:$PATH"' >> ~/.bash_profile
```

言われたとおりにパスを通します。

```bash
# パスを通す
$ echo 'export PATH="/usr/local/opt/php@7.1/bin:$PATH"' >> ~/.bash_profile
$ echo 'export PATH="/usr/local/opt/php@7.1/sbin:$PATH"' >> ~/.bash_profile
$ source ~/.bash_profile

# インストール確認
$ which php
/usr/local/opt/php@7.1/bin/php
```

まずはPHPが無事に入りました。

### XDebugのインストール
以前はbrewから`brew install php71-xdebug`とかで入ったんですが、これも使えなくなりました。
代わりに、peclを使ってインストールします。phpをインストールすると自動で入っているはず。

```bash
$ which pecl
/usr/local/opt/php@7.1/bin/pecl
$ pecl install xdebug
```

長いインストールログの後、

```
Build process completed successfully
Installing '/usr/local/Cellar/php@7.1/7.1.20/pecl/20160303/xdebug.so'
install ok: channel://pecl.php.net/xdebug-2.6.0
Extension xdebug enabled in php.ini
```

と吐き出してくれます。
が、私の環境ではまだ使えませんでした。全然enabledされてない。

### XDebugを設定する
このインストーラーは、必要な設定を`php.ini`の**先頭**に追記するようなのですが、私の環境ではこの自動設定だと動きませんでした。例えばモジュール一覧を出そうとすると、以下のようなエラーが出てきます。

```bash
$ php -m
Failed loading /usr/local/Cellar/php@7.1/7.1.20/lib/php/20160303/xdebug.so:  dlopen(/usr/local/Cellar/php@7.1/7.1.20/lib/php/20160303/xdebug.so, 9): image not found
```

[Macにもともと入ってるPHP7\.1にxdebugを入れる方法（2018年7月版）](https://qiita.com/NakanishiTetsuhiro/items/19012ca88ce501a6f6a4) を見ると、どうやら別の場所に`xdebug.so`が存在するようなので、そちらに設定を書き換えます。ついでに、`php.ini`の末尾に記述を移動し、必要な設定を付け加えます。

```ini:/usr/local/etc/php/7.1/php.ini
# 先頭に追加された以下の行を削除
zend_extension=xdebug.so

# 以下末尾に記載
[XDebug]
zend_extension=/usr/lib/php/extensions/no-debug-non-zts-20160303/xdebug.so
xdebug.remote_enable=1
xdebug.remote_autostart=1
```

書き換えたら、phpを再起動します。

```bash
$ brew services restart php@7.1
```

これで無事に準備ができました。

```bash
$ php -v
PHP 7.1.20 (cli) (built: Jul 20 2018 10:27:12) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v2.5.5, Copyright (c) 2002-2017, by Derick Rethans
    with Zend OPcache v7.1.20, Copyright (c) 1999-2018, by Zend Technologies
```

## VSCodeでPHPデバッグ
### 初期設定
VSCodeでデバッグをする際は、[PHP Debug](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug) という拡張機能をインストールします。
その後、デバッグ画面の設定でPHP用の設定を追加します。デバッグ画面のサイドバー上部、歯車のマークから、PHP用の構成を追加します。

自動で開いた設定ファイル`/.vscode/launch.json`を見ると、

* Listen for XDebug
* Launch currently open script

の2つが追加されていますが、前者がWebサーバー用の設定です（後者はPHPファイルを直接CLIから起動するときのデバッグ設定）。
portが9000になっていますが、これがxdebugのデバッグ用ポート指定です。もし`php.ini`の中で`xdebug.remote_port`の値を変更している場合、ここもその指定に合わせます。

### デバッグしてみる
設定ができたら、デバッグを試してみます。
適当なPHPを用意し、ブレークポイントを打ってみましょう（行番号の左側をクリックすると、赤丸でブレークポイントが表示されます。もう一度クリックで消えます）。

PHPの準備ができたら、サーバーを起動してみましょう。
Laravelを使っている場合は`php artisan serve`、それ以外なら`php -S localhost:8000`とかで起動します。9000番ポートを使わなければ大丈夫です。
ブラウザからアクセスし、正しく画面が表示されることを確認してください。

デバッグ画面サイドバーの緑色の三角ボタンを押すと、デバッグが開始されます。
その状態で再度ブラウザからアクセスすると、自動的にデバッグ画面が表示され、ブレークポイントで止まっているはずです。デバッグが非常に捗ります。

## 蛇足:Laravel 5系におけるXDebugでのデバッグ
Laravel 5系では、XDebugを使用したデバッグを行う際、プログラムと関係ない箇所で、必ず何回かブレークしてしまいます。

```
Illuminate\Contracts\Encryption\DecryptException: The payload is invalid.
```

例外処理によるブレークなので、ブレークしないように設定しても良いのですが、どうやらXdebugが発行するCookieが原因のようですので、[php \- Laravel 5 with Xdebug always throws "The payload is invalid\." \- Stack Overflow](https://stackoverflow.com/questions/47355311/laravel-5-with-xdebug-always-throws-the-payload-is-invalid)を参考に、以下のような記載を`EncryptCookies`に追加すると防ぐことができます。

```php:App\Http\Middleware\EncryptCookies.php
/**
 * The names of the cookies that should not be encrypted.
 *
 * @var array
 */
protected $except = [
    'XDEBUG_SESSION'
];
```

追加後は、以下のコマンドを実行します。

```bash
$ php artisan optimize
$ php artisan cache:clear
$ composer dump-autoload
```

これでもうまくいかない場合は、ブラウザのCookieを一度削除して、再度試してみてください。

それでは、よいデバッグライフをお過ごしください。