11

アプリケーション ロジックに大量のエラーが発生するのを回避し、isset()必要に応じてデバッグ メッセージ (E_NOTICE) を表示する機能を保持するためのより良い方法はどれですか?

最初の仮定: E_NOTICE はエラーではありません。これは誤称であり、実際には E_DEBUG である必要があります。ただし、これは設定されていない変数 (PHP は依然としてスクリプト言語です) には当てはまりますが、一部のファイル システム関数などもそれらをスローします。したがって、E_NOTICEs をオンにして開発することが望ましいです。

しかし、すべてのデバッグ通知が役立つわけではありません。そのため、アプリケーション ロジック全体で @を導入するのが一般的な (残念ながら) PHP のイディオムです。isset()確かに、isset/empty には多くの有効な使用例がありますが、全体的には構文ソルトのように見え、実際にデバッグを妨げる可能性があります。

そのため、現在、error_reporting ブックマークレットとダムのオン/オフ スイッチを使用しています。

// javascript:(function(){document.cookie=(document.cookie.match(/error_reporting=1/)?'error_reporting=0':'error_reporting=1')})()

if (($_SERVER["REMOTE_ADDR"] == "127.0.0.1")
    and $_COOKIE["error_reporting"])
{
    error_reporting(E_ALL|E_STRICT);
}
else {/* less */}

ただし、それでも、一度有効にすると検索するには通知が多すぎるという問題が残ります. 回避策として、@ エラー抑制演算子を利用できます。isset() とは異なり、カスタム エラー ハンドラは抑制された E_NOTICE を引き続き受け取る可能性があるため、デバッグ オプションを完全に削除するわけではありません。そのため、予想されるデバッグ通知を潜在的な問題から切り離すことが役立つ場合があります。

しかし、それは同様に満足のいくものではありません。したがって、質問です。より洗練された PHP エラー ハンドラを使用している、または知っている人はいますか。私は次のことを想像しています:

  • フィルター処理されていないエラー/警告/通知を出力します (CSS 絶対配置で?)
  • クライアント側の検査と抑制を可能にするAJAX-whatnot
  • だけでなく、予想される「承認された通知または警告のフィルタリング リストも保存します。

確かに、一部のフレームワークには、そのようなユーザー エラー ハンドラーが既にあるはずです。

  • 基本的には注意・告知管理に興味があります。
  • 完全な E_NOTICE 抑制は実際には望ましくありません。
  • E_NOTICES募集しています。それらの数が少ないだけです。デフォルトでは、期待されるものではなく、私が気にする可能性のあるものを強調表示します。
  • ?order= パラメータなしで実行すると、予想される NOTICE が発生します。当然のことながら、何度も通知する必要はありません。
  • ただし、完全なデバッグ モードでは、上記のデバッグ通知の存在 (または、より興味深いことに不在) を通じて、未定義の変数の存在を確認したいと考えています。-> そのためにあると思います。isset を回避すると、言語暗黙の print ステートメントが発生します。
  • また、これは通常の PHP フォーム処理セマンティクスが適しているユース ケースに関するものであり、厳密さが必須であるアプリケーション領域ではないことも理解してください。

ああ、誰かこれを書き直すのを手伝ってください。長い説明は失敗します。

4

9 に答える 9

9

E_NOTICE をまったく発行しない大規模な PHP アプリケーションを開発することは可能です。あなたがしなければならないことは、通知が発行される可能性のあるすべての状況を回避することです。その大部分は、初期化されていない変数と存在しない配列キーです。isset()残念ながら、これは回避したいというあなたの希望と衝突しますarray_key_exists()

慎重にフレームワークを構築することで、せいぜいそれらの使用を最小限に抑えることができます。これは通常、(たとえば)入力レイヤーを意味GETし、期待する変数と欠落している変数のデフォルト値を指定します。そうすれば、ページ固有のコードには常に参照する値があります。一般に、これはさまざまな API に適用できる価値のある手法です。しかし、これが優先度の高い設計目標であるべきかどうかは疑問です。

他のいくつかの言語とは異なり、PHP は変数が存在しないことと、一般に「空の」値 (通常は ) を含むことを区別しますnull。これはおそらく以前のバージョンの設計上のアーティファクトですが、それでも存在するため、実際に回避することはできません。

于 2010-11-15T00:11:48.987 に答える
6

私は変数と変数isset()のみを使用しており、データはアプリケーションの制御外から取得されます。そして、それを回避するための適切なOOPソリューションを作成する時間がない他の状況で使用していますが、すべてではないにしてもほとんどの場所で回避できると確信しています。たとえば、連想配列の代わりにクラスを使用することをお勧めします。これにより、配列キーの存在を確認する必要がなくなります。$_GET$_SERVER

私のアドバイスは次のとおりです。

  • @演算子の使用は避けてください
  • Xdebugを使用します。まず、すべての通知/警告に関する読みやすく、わかりやすいメッセージを出力し、例外に関する非常に便利なスタックトレースを出力します(すべてのメソッドパラメーターとすべてのローカル変数(xdebug.collect_params=4およびxdebug.show_local_vars=on構成パラメーター)を出力するように構成できます)。構成値を使用して@オペレーターを無効にすることができます。プロファイリングおよびコードカバレッジ分析にもxdebug.scream=1Xdebugを使用できます。これは、開発マシンに必須です。
  • デバッグにはFirePHPも使用しています。これは、 Firebugで動作し、 Firebugコンソールにメッセージを出力できるため、 AJAXデバッグにも使用できるためです。
  • カスタムエラーハンドラを使用すると、エラーや警告をキャッチしてフィルタリングしたり、ファイルにログインしたり、FirePHPで表示したり、jGrowlGritterなどを使用してWebページに適切に表示したりできます。

PHPマニュアルの例の修正バージョンを使用しています:

<?php
//error_reporting(0);
set_error_handler("errorHandler");

function errorHandler($errno, $errstr, $errfile, $errline)
{
    echo "errorHandler()<br />\n";

    // filter out getImageSize() function with non existent files (because I'am avoiding using file_exists(), which is a costly operation)
    if ( mb_stripos($errstr, 'getimagesize') !== false )
        return true;

    // filter out filesize() function with non existent files
    if ( mb_stripos($errstr, 'filesize') !== false )
        return true;

    // consoleWriter is my class which sends the messages with FirePHP
    if (class_exists('consoleWriter'))
        consoleWriter::debug(array('errno'=>$errno, 'errstr'=>$errstr, 'errfile'=>$errfile, 'errline'=>$errline, 'trace'=>debug_backtrace()), "errorHandler");

    switch ($errno) {
    case E_USER_ERROR:
        $out .= "<b>FATAL_ERROR</b> <i>$errno</i> $errstr<br />\n";
        $out .= "Fatal error on line $errline in file $errfile";
        echo "</script>$out";   // if we were in a script tag, then the print is not visible without this
        //writeErrorLog($out);

        echo "<pre>";
        var_export(debug_backtrace());
        echo "</pre>";

        exit(1);
        break;

    case E_USER_WARNING:
        $out .= "<b>WARNING</b> <i>$errno</i> $errstr<br />\n";
        $out .= "On line $errline in file $errfile<br />\n";
        break;

    case E_USER_NOTICE:
        $out .= "<b>NOTICE</b> <i>$errno</i> $errstr<br />\n";
        $out .= "On line $errline in file $errfile<br />\n";
        break;

    default:
        $out .= "<b>Unknown</b> <i>$errno</i> $errstr<br />\n";
        $out .= "On line $errline in file $errfile<br />\n";
        break;
    }

    if (!class_exists('consoleWriter'))
        echo $out;

    //writeErrorLog($out);
    //addJGrowlMessage($out);

    // Don't execute PHP internal error handler
    return true;
}

function testNotice($a)
{
    echo $a;
}
testNotice();

もう1つのアドバイスは、phpのみのファイルの最後に終了タグを使用しないこと?>headers already sentです。これは、出力バッファリングがデフォルトで無効になっている構成でエラーが発生する可能性があるためです。

于 2010-11-18T19:23:44.540 に答える
2

ベストプラクティスに従うことは時間の無駄ではないと思います。確かに、通知はエラーではありませんが、変数の宣言と検証が正しいと、コードがより読みやすく安全になります。ただし、debug_backtraceを使用してユーザー定義のエラーハンドラーを記述し、正規表現を使用してE_NOTICE(8)をソートすることはそれほど複雑ではありません。

于 2010-11-14T23:58:48.413 に答える
2

試してくださいxdebug-http ://www.xdebug.org/docs/stack_trace

たくさんのissetチェックはあなたに害を与えません、

実際、使用する前に変数を宣言することをお勧めします

于 2010-11-11T19:43:18.873 に答える
2

PHP は間違いなく、コードが読みにくくなっています。「null」は「未定義」を意味します - 簡単です。

コードを読めなくするこの問題に遭遇したときに私がすることは次のとおりです。

/**
 * Safely index a possibly incomplete array without a php "undefined index" warning.
 * @param <type> $array
 * @param <type> $index
 * @return <type> null, or the value in the index (possibly null)
 */
function safeindex($array, $index) {
  if (!is_array($array)) return null;
  return (isset($array[$index])) ? $array[$index] : null;
}

// this might generate a warning
$configMenus = $config['menus'];  

// WTF are you talking about!!  16 punctuation marks!!!
$configMenus = (isset($config['menus']) ? $config['menus'] : null;

// First-time awkward, but readible
$configMenus = safeindex($config, 'menus');

この回答をここにクロス投稿します。これはスパムチェッカーに役立ちますか?

于 2011-04-06T17:30:18.830 に答える
2

私も似たような欲求がありました。そこで、カスタム エラー ハンドラの使用を開始しました。

http://php.net/manual/en/function.set-error-handler.php

次に、エラー/通知を表示/ログ記録するための独自のフィルター/メカニズムを作成できます。

乾杯!

于 2010-11-15T22:15:01.713 に答える
1

私の意見では避けるための最良の方法isset()は、変数を使用する前に変数を定義することです。isset()私はそれが醜いのでそれほど嫌いではありませんが、それは悪いプログラミング慣行を助長するからです。

エラー処理自体については、すべての情報をサーバーログに出力します。php -lまた、コマンドラインで使用して、事前にプログラムの構文をチェックします。私はデフォルトでユーザーにきれいなメッセージを送ります。

さまざまなフレームワークの1つを調べて、それらのいずれかが機能するかどうかを確認できます。私が見たそれらのほとんどには、PHPがすぐに提供するものよりも簡単にするためのエラー処理ルーチンがあります。

編集: @mario-あなたのコメントに対する私の応答は長くなりすぎていました:-)。私は型を定義したり、JavaやCのようなある種の厳密な形式に移行したりすることを推奨していません。使用されているコンテキストで変数を宣言することを推奨しています。($foo = null;変数を空白のままにすることと同じではありません)。

これは、多くの場合、特にGETおよびPOSTデータを取得するためのスーパーグローバルでは、グローバル変数の問題であると思います。PHPが入力データを取得するためのクラスを優先して、スーパーグローバルを削除することを本当に望んでいます。このようなもの(非常に単純ですが、具体的なものが必要でした::))

<?php
class PostData {
     private $data;

     public function __construct() {
          $this->data = $_POST;
          unset($_POST);
     }

     public function param($name, $value = null) {
          if( $value !== null ) {
               $this->data[$name] = $value;
          }

          if( isset( $this->data[$name] ) ) {
               return $this->data[$name];
          }
          return null;
      }
}
?>  

param()クラスを含めると、メソッドからPOSTデータを取得および設定できます。また、検証を入力データに組み込むための優れた方法でもあります。そしてボーナスとして、すべてをチェックする必要はありませんisset()(すでにそうです)。

于 2010-11-11T19:42:46.250 に答える
1

今では時代遅れの答えですが、当時は柔軟なログディスパッチャーを使用していましたhttps://github.com/grosser/errorhandler (正確にはIIRCを探していたものではありませんが、少なくとも交互に行うよりも少し洗練されています)完全および部分的な抑制。)

とにかく、私はその間、最も一般的なケースに$_GET->int["input"]ラッパーを使用しています。これは単純な ArrayAccess ラッパーであり、存在しない var を暗黙的にキャッチし、通知の回復を容易にします。(ただの副産物です。ただし、主に即時のフィルタリングを目的としています。)

また、別のプロジェクトでは、プリプロセッサ マクロを使用してIFSET@($var)、ビルド パラメータに応じて有効化/無効化またはログ リダイレクトを許可しています。

于 2010-11-22T04:52:30.803 に答える