読者です 読者をやめる 読者になる 読者になる

by shigemk2

当面は技術的なことしか書かない

縁の下の力持ちxdebugの縁の下! #phpcon2012

PHPカンファレンス 2012

アシアルの中の人

xdebugの実装を調べてみたら、PHPの裏側の仕組みと連携していた

xdebugとは?

拡張ライブラリ
デバッグや開発を支援してくれる

どんな仕組み?

php/php-src
xdebug

ソースコードを取得してみたら?

コードカバレッジ取得

用途 テストの網羅率を調べる

xdebug_start_code_coverage();で簡単に調べられるよ。

<?php
xdebug_start_code_coverage();

function fuga() {
  echo "fuga";
}

echo 'fuga';
fuga();

var_dump(xdebug_get_code_coverage());

実行された行を表示してる。

fugafugaarray(1) {
["/hogehoge.php"]=>
array(6) {
[4]=>
int(1)
[5]=>
int(1)
[6]=>
int(1)
[8]=>
int(1)
[9]=>
int(1)
[11]=>
int(1)
}
}

どういう仕組みで動いているのか?

裏側ではどうやって動作しているのか

  1. 字句解析(コードをトークの列に格納)
  2. 構文解析(トークン列から構文を解析)
  3. コンパイル(ZendEngine用のコードにコンパイル)
  4. 実行(zend_op_array構造体を解釈してそれを実行、関数、メソッドやファイル読み込みのたびに呼ばれる)

ファイル、関数、メソッド ヒトツニツキzend_op_array構造体に格納
ZendEngine用のコンパイルされたコード
zend_op構造体の列が入っている

zend_op構造体
zendEngineへの命令を表現
命令の種類は多数

PHPでは…
コードをzend_op_array構造体に変換、zend_execute関数に渡して実行

初期化部分で、色々初期化する
zend_set_user_opcode_handler ZendEngineの振舞いを変えるAPI
特定のzend_op命令を解釈して実行する

zend_op実行時の現在の行を記録
実際に実行されたコードの行が分かる

コードカバレッジ取得の仕組みのまとめ

ZendEngineの拡張のためのAPIを利用
zend_set_user_opcode_handlerの命令をフックして、実行を記録している

関数トレース

実行した関数をトレースして状態を記録する

xdebug_start_trace( 'C:/Temp/log' );
function hoge($i = 10){
  echo $i . PHP_EOL
  if(0 < $i ) {
    hoge(--$i);
  }
}

みたいな。

呼び出し時の状態をトレースに保存
その後本来の実行関数を呼び出す

zend_execute ではなく、 xdebug_execute関数を呼び出す
zend_executeをまるまるすげかえて、関数呼び出しをフック
その後本来の実行関数を呼び出して、ログファイルに記録

リモートデバッグ

ブレークポイント ステップ実行などをやってくれる

PHP + xdebug と DBGPデバッガでやりとりを行っている。
DBGP デバッガ用通信プロトコルを使用してリモートデバッグを実行している
ブレーク時にはDBGPデバッガの命令を待つ

statement_handler
すべての構文の実行ごとに呼び出されるフック (毎回呼ばれる)

xdebug/xdebug.c 1853あたり

  1. xdebug_statement_call内で止まっている
  2. 止まっている間は、DBGPデバッガからの命令を待っている。
  3. フックのなかでデバッガに接続

PHPにはフックできるところがたくさんある。