デバック

プログラミングエラー

構文に誤りがある

デバックとは、プログラムの不都合によりエラーが生じるといったバグの原因を調べ、問題を解決する一連の作業のことをいいます。

PHPには、プログラミングエラーの検出や診断する環境が整えられており、エラーの種類とそれぞれの対処法を身に付ければ、エラーを即座に解決できるようになります。

例えば、スクリプトの構文に誤りがあると、スクリプトを実行する前にエラーを検出して、エラーメッセージを表示する機能があります。

構文エラーを含むスクリプト「name.php」

    01: <?php
    02:     define( "name", "山田 花子" ;
    03:     echo name;
    04: ?>
    

実行結果

Parse error: syntax error, unexpected ';' in C:¥sample¥name.php on line 2

上記のスクリプトでは2行目に「 ) 」(閉じ括弧)がありません。

エラーメッセージには、エラーが発生した行番号が表示されています。エラーの箇所さえ見当がつけば、修正が楽になります。

しかし、下記のスクリプトのように、エラーメッセージの行番号からだけでは、エラーの発生場所がわからない場合もあります。

見つけにくい構文エラーを含む「fruit.php」

    01: <?php
    02:     $grape = "りんご";
    03:
    04:     if($grape == "ぶどう")
    05:
    06:         echo "これはぶどうです";
    07:
    08:     } else {
    09:
    10:         echo "これはぶどうではありません";
    11:     }
    12: ?>
    

実行結果

Parse error: syntax error, unexpected ';' in C:¥sample¥fruit.php on line 8

上記のエラーメッセージの行番号が示す8行目には、構文的な誤りはありません。

そこで、この場合には、8行目のelseを要素とするif文全体の構文エラーであることが推測できます。よく調べてみると、4行目に「 { 」(中括弧)がないことに気づきます。

PHPのエラー検出機能はとても便利ですが、エラーメッセージの行番号が示す場所が必ず誤っているとは限りません。エラー箇所の見当がつかなければ、エラーメッセージの行番号が示す付近や、要素内などを一行ずつ調べる必要があります。

意味を解釈できない

PHPではスクリプトの構文が正しくても、意味を解釈できなければエラーメッセージを表示します。構文としては誤りがないため、スクリプトを実行する前に検出できません。実行してはじめてエラーであることがわかります。

引数に指定したパスが間違っている「file_open.php」

    01: <?php
    02:     $file = fopen( "../../template/sample.text", "r" );
    03:     $str = fread( $file, 6 );
    04:
    05:     echo "$str";
    06:     fclose( $file );
    07: ?>
    

実行結果

Warning: fopen(../template/sample.text) [function.fopen]: failed to open stream: No such file or directory in C:¥sample¥file_open.php on line 2
Warning: fread(): supplied argument is not a valid stream resource in C:¥sample¥file_open.php on line 3
Warning: fclose(): supplied argument is not a valid stream resource in C:¥sample¥file_open.php on line 6

上記のスクリプトでは、2行目のfopen()関数の引数に、開くファイルまでの相対パスを指定しています。

しかし、指定した場所に「template」ディレクトリが存在しなかった場合、あるいは、指定した相対パスが誤っていた場合、スクリプトを一通り実行した後、エラーメッセージが表示されます。

エラーメッセージを表示させない

fopen()関数で起こるエラーのように、何かのファイルを読み込んだり、データベースに接続する場合、たいてい引数のパスが存在しないファイルを指定したり、誤ったパスを指定したりといったミスでエラーになることが多く見受けられます。

例えば、本番環境で仮にエラーが起こったとして、PHPからのエラーメッセージが表示された場合、そのエラーメッセージには外部から見られたくない情報が含まれているといったこともあります。

エラーメッセージが出力されることで、ファイルの置き場所や構成が露出してしまい、セキュリティ上問題になるといった可能性も出てきます。

そこでPHPには、仮にエラーが発生した場合、生成されるエラーメッセージを表示させない「@」エラー制御演算子というものが存在します。

例えば、先ほど上記でエラーが発生した「file_open.php」を試用してみます。

エラーメッセージを表示させないエラー制御演算子

    <?php
        $file = @fopen( "../../template/sample.text", "r" ) or die( "ファイルが存在しません" );
        $str = fread( $file, 6 );

        echo "$str";
        fclose( $file );
    ?>
    

実行結果

ファイルが存在しません

上記のスクリプトでは、fopen()関数の前に「@」をつけて、PHPエンジンによって生成されるエラーメッセージを無視しています。仮にファイルが存在した場合は、dieで処理を終了せずにそのまま最後まで実行します。

「@」エラー制御演算子は、変数、関数、include()コール、定数等の前につけることが可能です。関数またはクラスの定義や、ifやforeach等の条件構造の前にこの演算子を付けることはできません。

また、行末に「;」セミコロンを付け忘れたり、「 ) 」(閉じ括弧)を付け忘れたりといった構文の誤りに関しては、エラー制御演算子「@」でも回避できません。

論理的に間違っている

論理エラーは、構文的にも意味的にも誤りがないエラーです。よって、エラーメッセージや警告が表示されることはありません。

論理エラーを防ぐためには、プログラムの設計段階で誤りを含まないように心掛けることが大切です。論理エラーは、プログラムの出力結果を一つ一つ丁寧に検証することによって、はじめて発見することができます。

echoで論理エラーを発見する

    <?php

        for( $i=0; $i<10; $i++ ) {

    // 1つめのチェックポイント
    echo "CheckPoint1";

            if( $i<$number ) {

    // 2つめのチェックポイント
    echo "CheckPoint2";

                $syouhin_code = CC_DBresult( $result, $i, "syouhin_code" );
                $b_category_name = substr( CC_DBresult( $result, $i, "b_category_name" ), 0, 16 );
                $syouhin_name = substr( CC_DBresult( $result, $i, "syouhin_name" ), 0, 30 );
                $keisaibi = substr( str_replace( "-", "/", CC_DBresult( $result, $i, "keisaibi" ) ), 8 );
                $keisai_kigen = CC_DBresult( $result, $i, "keisai_kigen" );
                $admin_name = substr( CC_DBresult( $result, $i, "admin_name" ), 0, 12 );
                $syouhin_fg = CC_DBresult( $result, $i, "syouhin_fg" );

                if( $syouhin_fg == 1 ) {

                    $status = "承認";

    // 3つめのチェックポイント
    echo "CheckPoint3";

                } else if( $syouhin_fg == 9 ) {

                    $status = "未承認";

    // 4つめのチェックポイント
    echo "CheckPoint4";

                }

                $access_count = CC_DBresult( $result, $i, "access_count" );

            } else {

                $syouhin_code = "";
            }

                                             :
                                             :
                                             :
                                             :
                                             :
                                             :
                                             :
                                             :
                                             :
                                             :
                                             :
                                             :
    

上記のスクリプトのように、forやifなどを何度も使用した複雑なスクリプトで論理エラーが発生した場合、順を追ってチェックしていくしかありません。

理論エラーを発見する手段として、上記のようにechoなどを使用して、どこからどこまで処理が進んでいるかを確認しながら、上から順にチェックしていく方法などもあります。

エラーメッセージ

パースエラー(parse error)

パースエラーは、構文のエラーに対して表示されるエラーメッセージです。

例えば、「;(セミコロン)」が抜けていたり、「{(カッコ)」が閉じられていなかったりなど、スクリプトの構文に誤りがあると、スクリプトを実行する前にエラーを検出して、メッセージを表示します。

パースエラーのメッセージ

Parse error: syntax error, unexpected ';' in C:¥sample¥name.php on line 2

PHPのパースエラーは、下記の形式で表示されます。

エラーレベル: エラーメッセージ in ファイル名 on 行番号

致命的エラー(fatal error)

フェイタルエラーは、致命的エラーという意味で、スクリプトが正しく動作しないので処理が中断されます。エラーを取り除かない限りスクリプトを実行できません。

未定義関数の呼び出しに対する致命的エラー

Fatal error: Call to undefined function job() in C:¥sample¥fatal.php on line 4

警告(warning)

ワーニングは、スクリプトを実行できないようなエラーを含んでいた際に表示されます。

しかし、PHPはスクリプトを実行していくため、一つのエラーが次のエラーを引き起こし、さらに多くのエラーを発生させることになります。

警告(Warning)エラーの原因を含むスクリプト

Warning: fopen(../template/sample.text) [function.fopen]: failed to open stream: No such file or directory in C:¥sample¥file_open.php on line 2
Warning: fread(): supplied argument is not a valid stream resource in C:¥sample¥file_open.php on line 3
Warning: fclose(): supplied argument is not a valid stream resource in C:¥sample¥file_open.php on line 6