web-dev-qa-db-ja.com

警告を試す/キャッチすることはできますか?

Phpのネイティブ関数からスローされる警告をキャッチして、処理する必要があります。

具体的には:

array dns_get_record  ( string $hostname  [, int $type= DNS_ANY  [, array &$authns  [, array &$addtl  ]]] )

DNSクエリが失敗すると、警告がスローされます。

警告は例外ではないため、try/catchは機能しません。

現在、2つのオプションがあります。

  1. set_error_handlerは、ページ内のすべての警告をフィルター処理するために使用する必要があるため、やりすぎのようです(これは本当ですか?)。

  2. これらの警告が画面にエコーされないようにエラー報告/表示を調整してから、戻り値を確認してください。 falseの場合、ホスト名のレコードは見つかりません。

ここでのベストプラクティスは何ですか?

320
user121196

エラーハンドラーの設定と復元

可能性の1つは、呼び出しの前に独自のエラーハンドラを設定し、restore_error_handler()を使用して前のエラーハンドラを後で復元することです。

set_error_handler(function() { /* ignore errors */ });
dns_get_record();
restore_error_handler();

この考えに基づいて、エラーを記録する再利用可能なエラーハンドラを作成できます。

set_error_handler([$logger, 'onSilencedError']);
dns_get_record();
restore_error_handler();

エラーを例外に変換する

set_error_handler()およびErrorExceptionクラスを使用して、すべてのphpエラーを例外に変換できます。

set_error_handler(function($errno, $errstr, $errfile, $errline, array $errcontext) {
    // error was suppressed with the @-operator
    if (0 === error_reporting()) {
        return false;
    }

    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});

try {
    dns_get_record();
} catch (ErrorException $e) {
    // ...
}

独自のエラーハンドラーを使用する場合に注意すべき重要な点は、error_reporting設定をバイパスし、すべてのエラー(通知、警告など)をエラーハンドラーに渡すことです。 set_error_handler()に2番目の引数を設定して、受信するエラータイプを定義するか、エラーハンドラー内で... = error_reporting()を使用して現在の設定にアクセスできます。

警告の抑制

もう1つの可能性は、@演算子での呼び出しを抑制し、その後dns_get_record()の戻り値を確認することです。 ただし、これにはお勧めしますエラー/警告は抑制されるのではなく、処理されるようにトリガーされます。

341
Philippe Gerber

実際に動作する解決策は、次のようにE_WARNINGパラメーターを使用して単純なエラーハンドラーを設定することでした。

set_error_handler("warning_handler", E_WARNING);
dns_get_record(...)
restore_error_handler();

function warning_handler($errno, $errstr) { 
// do something
}
135
Robert

@演算子に注意してください-警告を抑制しますが、致命的なエラーも抑制します。誰かが@mysql_query( '...' )を書いたシステムで問題をデバッグするのに多くの時間を費やしましたが、問題はmysqlサポートがPHPにロードされず、静かな致命的エラーを投げたことでした。 PHPコアの一部であるものは安全ですが、please慎重に使用してください。

bob@mypc:~$ php -a
Interactive Shell

php > echo @something(); // this will just silently die...

これ以上の出力はありません。これをデバッグしてください。

bob@mypc:~$ php -a
Interactive Shell

php > echo something(); // lets try it again but don't suppress the error
PHP Fatal error:  Call to undefined function something() in php Shell code on line 1
PHP Stack trace:
PHP   1. {main}() php Shell code:0
bob@mypc:~$ 

今回は失敗した理由を見ることができます。

27
GuruBob

警告を試し/キャッチしたかったのですが、同時に通常の警告/エラーロギングを保持しました(例:/var/log/Apache2/error.log);ハンドラーはfalseを返す必要があります。ただし、「throw new ...」ステートメントは基本的に実行を中断するため、次に説明する「関数でラップ」トリックを実行する必要があります。

PHPで例外をスローする静的な方法はありますか

または、簡単に言うと:

  function throwErrorException($errstr = null,$code = null, $errno = null, $errfile = null, $errline = null) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
  }
  function warning_handler($errno, $errstr, $errfile, $errline, array $errcontext) {
    return false && throwErrorException($errstr, 0, $errno, $errfile, $errline);
    # error_log("AAA"); # will never run after throw
    /* Do execute PHP internal error handler */
    # return false; # will never run after throw
  }
  ...
  set_error_handler('warning_handler', E_WARNING);
  ...
  try {
    mkdir($path, 0777, true);
  } catch (Exception $e) {
    echo $e->getMessage();
    // ...
  }

編集:綿密な検査の後、それは動作しないことが判明しました:「return false && throwErrorException ...」は基本的に、notが例外をスローし、ログインするだけですエラーログ。 「false &&」のように「return throwErrorException ...」部分を削除すると、例外のスローが機能するようになりますが、error_logにログインしません。他の場所。

5
sdaau

通常、これが唯一の解決策でない限り、@は使用しないでください。その特定の場合、関数dns_check_recordを最初に使用して、レコードが存在するかどうかを確認する必要があります。

4
florynth

おそらく警告を完全に取り除こうとする必要がありますが、それが不可能な場合は、呼び出しの前に@(つまり@dns_get_record(...))を追加し、警告が発生したかどうかを把握できる情報を使用できます。か否か。

4
rpjohnst

外部URLへのfile_get_contents()呼び出しにこれらのコード行を組み合わせると、「ストリームを開くことができませんでした:接続がタイムアウトしました」のような警告を処理するのに役立ちました。

set_error_handler(function ($err_severity, $err_msg, $err_file, $err_line, array $err_context)
{
    throw new ErrorException( $err_msg, 0, $err_severity, $err_file, $err_line );
}, E_WARNING);
try {
    $iResult = file_get_contents($sUrl);
} catch (Exception $e) {
    $this->sErrorMsg = $e->getMessage();
}
restore_error_handler();

このソリューションは、オブジェクトコンテキスト内でも機能します。関数で使用できます:

public function myContentGetter($sUrl)
{
  ... code above ...
  return $iResult;
}
3
Bugfighter

dns_get_record()が失敗した場合、FALSEを返す必要があるため、@で警告を抑制してから戻り値を確認できます。

2
Amber

ブール値を返すかどうかを確認してから、単純に条件として配置できます。私は、oci_execute(...)でこれに遭遇しました。

ex.
oci_parse($res, "[Oracle pl/sql]");
if(oci_execute){
...do something
}
0
gborjal