Vdebugを使ってVimでPHPのデバッグ環境を整える

PHPはずっとPHPStormで書いていて不自由はなかったのですが、最近他の言語でvimを使いだしたところ、全部vimでやりたくなる一過性の病にかかったのでPHPでデバッグ環境を整えています。

PHPのxdebugを実行するのにvimのプラグインVdebugを使います。
[vim\-vdebug/vdebug: Multi\-language DBGP debugger client for Vim \(PHP, Python, Perl, Ruby, etc\.\)](https://github.com/vim-vdebug/vdebug)

全部マニュアルに書いてあるので読めば終了なんですが、せっかく触りながらマニュアルの内容を確かめたので備忘として残しておきます。
ただし、CLIでローカル実行した場合についてです。
ブラウザからのリクエストで起動する場合やリモートデバッグはまたいつか追記するかもしれません。

<実行中の雰囲気>
![phpdbg-memory-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14241/fc7f0763-1317-b6f2-7b55-c84a772c3db4.gif)

## インストール・初期設定
xdebugのインストールはすでにたくさん記事があるので省略。

### Vdebugのインストール
僕はPlugin managerに[junegunn/vim\-plug](https://github.com/junegunn/vim-plug)を使っています。

```vimscript:.vimrc
call plug#begin('~/.vim/plugged')
" Debug
Plug 'vim-vdebug/vdebug'

call plug#end()
```

.vimrcに追記してから

```
:PlugInstall
```

### 呼び出しスクリプトの作成
また、CLIから実行する場合は、環境変数`XDEBUG_CONFIG`で`idekey`の指定が必要です。毎回打つのが面倒なのでショートカット用のshellscriptを作ります。

```shell:php-xdebug
#!/bin/bash
export XDEBUG_CONFIG="idekey=xdebug"
/usr/bin/php "$@"
```

phpのパスは環境に合わせます。
実行権限付与して適宜パスの通っている場所に移します。

```
$ chmod +x php-xdebug
$ mv php-xdebug /to/your/path/
```
こんな風に使用。

```bash
$ php-xdebug myscript.php
```

## 使い方
### 基本の使い方

1. 止めたい行にブレークポイントを設置（F10)
2. Debuggerをスタート（F5）
3. Terminal別タブでそのブレークポイントを通過する処理を呼び出し
4. Debuggerをストップ（F6を２回）

### windowの見方
各windowはこんな感じになります。
<img width="688" alt="スクリーンショット 2020-06-13 23.02.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14241/f292a601-3c71-48ac-97a6-eaa57460beb0.png">

### よく使うキーバインド
- F5・・Start
- F6・・Stop
- F2・・Step Over
- F3・・Step In
- F4・・Step Out
- F9・・Run To Cursor
- F10・・Toggle Break Point

### ブレークポイント
- F10でtoggle
- `:BreakpointWindow`でブレークポイント一覧を確認
    - このウィンドウで消したいブレークポイントの行にカーソルをあわせて `dd` で該当ブレークポイントを削除
- `:BreakpointRemove *` で一括削除

### いろんなブレークポイント
F10の通常の行ブレークポイント以外にいくつかの特性を持ったブレークポイントを利用できます。

```:使い方
:Breakpoint <type> <arguments>
```
#### conditional
行ブレークポイントと似ていますが、ブレークが発動する条件を指定できます。
使い所は「ループの◯回目のみ止めたい」とかですかね。
標準の行ブレークポイント以外では唯一これだけ使いそうな気がします。


```:例）$xが2の場合のみブレーク
:Breakpoint conditional $x == 2
```

#### exception
指定した例外が発生した場合にブレークする

```:例
:Breakpoint exception PDOException
```

#### call
指定の関数が呼び出された場合にブレークする。マニュアルを見るに、挙動は保証されていないようです。

```
:Breakpoint call open_file
```
#### return
指定の関数からreturnされた場合にブレークする。同じく、挙動は保証されていないようです。

```
:Breakpoint return open_file
```

#### watch
指定の変数に書き込みがあった場合にブレークする。マニュアルにはxdebugでサポートされていないので期待するなと書いてあります。僕の環境では動かなかったです。特に期待してなかったので大丈夫でした。

```
:Breakpoint watch $myvar
```

### 任意の式の評価
実行ポイントのコンテキストで任意の式を評価させることができます。デバッガーの醍醐味とも言える機能ですね。
実行方法が3種類あります。

#### 1) 記述した式を評価する方法

```
:VdebugEval $x * 3
```

これはwatch windowに表示されますが、ステップを進めるとデフォルトのwatch windowに戻ります。
指定した式の評価をwatch windowに固定表示させたい場合は`:VdebugEval!`を使います。


```
:VdebugEval! $x * 3
```

デフォルトのwatch windowに戻したい場合は式無しで以下を打ち込みます

```
:VdebugEval!
```

#### 2）visualモードで選択した式を評価する方法
`v` で選択後 `<leader>e` で評価

#### 3) traceウィンドウで評価を確認する
`:VdebugTrace`を使うとwatch windowとは別にtrace windowで式をトレースできます。
`VdebugEval!`と似ていますが、watch windowをデフォルトとのままにしつつ式の評価を追うことができます。

```
:VdebugTrace $x
```

## 細かい設定とか
デフォルトオプション

```
    let g:vdebug_options = {
    \    'port' : 9000,
    \    'timeout' : 20,
    \    'server' : '',
    \    'on_close' : 'stop',
    \    'break_on_open' : 1,
    \    'ide_key' : '',
    \    'debug_window_level' : 0,
    \    'debug_file_level' : 0,
    \    'debug_file' : '',
    \    'path_maps' : {},
    \    'watch_window_style' : 'expanded',
    \    'marker_default' : '⬦',
    \    'marker_closed_tree' : '▸',
    \    'marker_open_tree' : '▾',
    \    'sign_breakpoint' : '▷',
    \    'sign_current' : '▶',
    \    'continuous_mode'  : 1,
    \    'simplified_status': 1,
    \    'layout': 'vertical',
    \}
```

個別で上書き

```:.vimrc
    if !exists('g:vdebug_options')
      let g:vdebug_options = {}
    endif
    let g:vdebug_options.port = 9001

```

まとめて上書き

```:.vimrc
let g:vdebug_options = {
    \   '"port' : 9000,
    \    'break_on_open' : 0,
    \    'ide_key' : '',
    \}
```

基本はデフォルトのまま使っていますが、`break_on_open`は0にしています。これは実行されるスクリプトの1行目でステップが止まるかどうかの指定です。ブレークポイントより前で止まっても鬱陶しいのでオフにしています。

#### レイアウト
`g:vdebug_options.layout`に`horizontal`を指定するとレイアウトがデフォルトから変わります。
![スクリーンショット 2020-06-23 21.46.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14241/8a5fa078-fd40-c063-a519-ffc9eb179ed9.png)


## 感想
- evaluationを複数同時にtraceできない点以外はIDEの場合とくらべて特に不便とかはなかったです。