第20章 デバッグ

エラーレポートの理解

PHPにはエラーレベルを設定する機能があります。初心者はこの概念を理解する必要があります。

// すべてのエラーを報告する
error_reporting(E_ALL);

// 注意: このコードには未定義の変数があるのでエラーが出力されます
echo $undefined_variable;

PHPのエラーレベルは下記になります。

定数 意味
1 E_ERROR 重大な実行時エラー。スクリプトは中断します。
2 E_WARNING 実行時の警告。スクリプトは中断しません。
4 E_PARSE コンパイル時のパースエラー
8 E_NOTICE 実行時の注意
16 E_CORE_ERROR PHPの初期始動時点での致命的なエラー
32 E_CORE_WARNING 致命的ではない警告
64 E_COMPILE_ERROR コンパイル時の致命的なエラー
128 E_COMPILE_WARNING コンパイル時の警告
256 E_USER_ERROR ユーザーによって発行されるエラーメッセージ。trigger_error()関数により発行
512 E_USER_WARNING ユーザーによって発行される警告メッセージ。trigger_error()関数により発行
1024 E_USER_NOTICE ユーザーによって発行される注意メッセージ。trigger_error()関数により発行
2048 E_STRICT 相互運用性や互換性を維持するためにコードの変更を提案
4096 E_RECOVERABLE_ERROR キャッチできる致命的なエラー
8192 E_DEPRECATED 将来のバージョンで動作しなくなるコードについての警告
16384 E_USER_DEPRECATED ユーザー定義の警告メッセージ。trigger_error()関数により発行
64 E_ALL 全てのエラーと警告

開発環境ではE_ALLで全てのエラーを表示し、本番環境ではエラー表示はOFFにし、ログには全てのエラーを記録する事が推奨されています。


カスタムエラーハンドラの作成

エラーハンドリングにカスタム関数を使用する方法も重要です。例えばエラー発生時にslackやメールに送信するなど可能とします。

function customErrorHandler($errno, $errstr) {
  echo "エラーが発生しました: [$errno] $errstr";
}

// カスタムエラーハンドラを設定
set_error_handler("customErrorHandler");

// エラーを発生させる
echo $undefined_variable;

全てのエラーレベルをハンドリングし、カスタム関数で条件分け
function specificErrorHandler($errno, $errstr, $errfile, $errline) {
    if ($errno === E_NOTICE) {
        echo "カスタム通知: $errstr\n";
        return true; // このエラーは処理済み
    }
    return false; // その他のエラーは標準のエラーハンドラに渡す
}

set_error_handler("specificErrorHandler");

// 未定義の変数を参照する(E_NOTICEエラーを発生させる)
echo $undefinedVariable;

一箇所で全てのエラーハンドリングを管理できるが、全てのエラーがハンドラに渡されるため、処理が効率的でない

第二引数を使用して必要なエラーレベルだけ記述
function noticeErrorHandler($errno, $errstr, $errfile, $errline) {
    echo "カスタム通知: $errstr\n";
}

// E_NOTICEレベルのエラーだけをハンドリング
set_error_handler("noticeErrorHandler", E_NOTICE);

// 未定義の変数を参照する(E_NOTICEエラーを発生させる)
echo $undefinedVariable;

// 0で割り算を行う(E_WARNINGエラーを発生させるが、このエラーハンドラでは処理されない)
$result = 10 / 0;

シンプルに記述でき処理も効率的だが、エラーレベル毎にカスタム関数を用意する必要がある

エラー処理のロジックが複雑で、各エラーレベルに対して異なる処理が必要な場合は、全てのエラーレベルをハンドリングして条件分けする方法が適しているかもしれません。

シンプルに特定のエラーレベルだけを処理したい場合、第二引数を使用した方法が効率的で可読性が高いでしょう。


デバッグツール

PHPのデバッグには、さまざまなツールとテクニックが利用できます。その中でもPHP自体に組み込まれた対話型のデバッグツールであるPHPDBGを紹介します。

PHPDBGの起動

phpdbgを起動するには、以下のコマンドを実行します。

phpdbg -q yourfile.php

一般的なコマンド

ブレークポイントの設定: 特定の行や関数でプログラムの実行を一時停止させることができます。

break filename.php:42 // 42行目でブレーク
break functionName  // 関数が呼び出される時にブレーク

ステップ実行: 一行ずつコードを実行し、進行状況を確認することができます。

step // 次の行へ進む
continue // 次のブレークポイントへ進む

変数の値の確認: 実行中の変数の値を確認することができます。

print $variable // 変数の値を表示

実行制御: プログラムの実行を制御することができます。

run // プログラムを最初から実行
quit // phpdbgを終了


使用例

以下は、簡単なPHPスクリプトをphpdbgでデバッグする例です。

function sayHello($name) {
    echo "Hello, " . $name . "!\n";
}

$name = "World";
sayHello($name);

このファイルをデバッグするために、以下のコマンドを実行します。

phpdbg -q example.php

デバッグセッションが開始されたら、ブレークポイントを設定して実行をコントロールすることができます。

break sayHello
run

これでsayHello関数が呼び出されるところで実行が一時停止します。

練習問題1.

以下のコードにはエラーが含まれています。何が問題なのかを特定し、どう修正すればよいかを考えてください。

function multiply($a, $b) {
  return $a * $c;
}

echo multiply(5, 3);


練習問題2.

以下のコードが警告を発生させるとします。set_error_handler関数を使用して、カスタムエラーハンドラを作成し、この警告をキャッチして独自のエラーメッセージを表示するようにコードを修正してください。

$number = 0;
$result = 10 / $number;
echo $result;


練習問題3.

以下のコードにバグがあります。phpdbgを使ってデバッグを行い、バグを見つける手順を説明してください。

function calculate($a, $b) {
  $result = $a - $b;
  return $result * $result;
}

$result = calculate(3, 5);
echo "The result is: " . $result; // 期待する結果は4