より複雑なプログラミングをするほどプログラムファイルも増え全体を把握するのが大変になってきます。
似たような関数が複数あり、今修正しなければいけない関数はどこだろうと悩む場面が出てくるでしょう。
僕はあまり頭がよくないので10年以上プログラミングをしているけど分からなくなることがあります(笑)
自分が作ったプログラムなら記憶の断片を繋ぎ合わせてなんとかたどり着けたりするのですが、他人が作ったものを修正するとなると本当に大変です!
そんなときに、指定した関数がどこから呼び出されたかを把握できる便利ツールがあれば嬉しいですよね?
実はPHPにはあるんです!
それが、debug_backtrace() という関数です。
今回はこれの使い方を説明します。
debug_backtrace()を使って呼び出し元を探るサンプルコード
呼び出し元を見つけるには、debug_backtrace() という関数を埋め込み実際に実行して結果を出力させます。
結果はログでも画面にでもいいですが、今回は画面に出力してみました。
以下のサンプルコードの仕様ですが、
- 水を貯めるポットクラス(Pot.php)
- ポットクラスを継承した電気ポットクラス(ElePot.php)
- 電気ポットクラスをインスタンス化して実行するPHPファイル(index.php)
を用意しました。
以前別の記事を書くのに作ったサンプルコードの流用です(笑)
Pot.php の水を追加する関数 addWater() がどこから呼ばれたかを特定していこうと思います。
ポットクラス
<?php
class Pot {
public $water = 0;
public function addWater($water) {
// どこから呼ばれたか出力する
echo "<pre>";
print_r(debug_backtrace());
echo "</pre>";
$this->water += $water;
}
public function getWater() {
return $this->water;
}
}
8行目で debug_backtrace() を実行し、print_r() で結果を出力しています。
7、9行目は<pre>タグといって、配列などを出力するときにきれいに整形されて便利です。
電気ポットクラス
<?php
require_once("Pot.php");
class ElePot extends Pot {
public $heat;
public function addWater($water) {
parent::addWater($water);
$this->heat = 4;
$this->doHeat();
}
public function doHeat() {
if($this->water > 0) {
$this->heat = 100;
$this->water *= 0.9;
}
}
}
Potクラスを継承し電気ポットクラス(ElePot)を定義します。
addWater() をオーバーライドして、その中で親クラス(Pot)の addWater() を呼び出しています。
ビュー
<?php
require_once("ElePot.php");
?>
<html>
<head>
<meta charset="UTF-8">
<title>PHPテスト</title>
<meta name="description" content="このページの概要を書く">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<?php
$pot = new ElePot();
$pot->addWater(100);
echo "ポットの中身=".$pot->getWater();
?>
</body>
</html>
URLを実行したときに一番最初に呼ばれるPHPファイルです。
13行目で電気ポットクラス(ElePot)をインスタンス化します。
14行目で addWater() を呼び出し、水を100追加しています。
15行目で現在の水の料を出力します。
実行結果
結果は以下のようになります。
Array
(
[0] => Array
(
[file] => C:\xampps\htdocs\sample\ElePot.php
[line] => 7
[function] => addWater
[class] => Pot
[object] => ElePot Object
(
[heat] =>
[water] => 0
)
[type] => ->
[args] => Array
(
[0] => 100
)
)
[1] => Array
(
[file] => C:\xampps\htdocs\sample\index.php
[line] => 14
[function] => addWater
[class] => ElePot
[object] => ElePot Object
(
[heat] =>
[water] => 0
)
[type] => ->
[args] => Array
(
[0] => 100
)
)
)
ポットの中身=90
結果は配列で取得できます。
1個目の配列は、debug_backtrace() を仕込んだメソッドがどこから実行されているかのデータです。
2個目の配列は、debug_backtrace() を仕込んだメソッドを実行したメソッドが、どこから実行されているかのデータです。呼び出し元の元です。
色々出力されていますが、見るポイントは2つで、[file]と[line]です。
1個目の配列の [file] は「C:\xampps\htdocs\sample\ElePot.php」で [line] は「7」となってます。
これは「C:\xampps\htdocs\sample\ElePot.php」の7行目で呼び出されたことになります。
電気ポットクラスのサンプルコードの parent::addWater($water); の行になりますね!
2個目の配列は
[file] => C:\xampps\htdocs\sample\index.php
[line] => 14
なので、index.php の14行目の $pot->addWater(100); になりますね!
簡単に呼び出し元を見つけることができちゃいました!すばらしい!!
ちなみに、一番最後の行は水の量を出力したものです。
まとめ
僕はPHPを使い始めて数年間この方法を知りませんでした・・・。
それまでは一生懸命コード読んだり検索したりして特定してたんですが、この方法を知ってからは今までの苦労がなんだったのか状態です。
一生懸命コード読んだり検索したりしたお陰でかなり上達したのもありますが。
でも、知ったならデバッグするときはこの debug_backtrace() を使わない手はないです!
がんがん使って仕事を効率化してください。










コメント