web-dev-qa-db-ja.com

PHPで@演算子を使用してエラーを抑制する

あなたの意見では、エラーを処理しているのに対して、@ =演算子を使用してPHPのエラー/警告を抑制することは有効ですか?

その場合、どのような状況でこれを使用しますか?

コード例は大歓迎です。

編集:回答者への注意。エラー報告をオフにするつもりはありませんが、たとえば、一般的な方法は

@fopen($file);

そしてその後チェックしてください...しかし、あなたはすることで@を取り除くことができます

if (file_exists($file))
{
    fopen($file);
}
else
{
    die('File not found');
}

または類似。

私は質問があると思います-エラーを抑制するために@ HASを使用する場所はどこにありますか?それは他の方法では処理できませんか?

67
Mez

エラーを抑制しますそしてそれを処理します。そうしないと[〜#〜] toctou [〜#〜] issue(チェック時間、使用時間。たとえば、file_existsがtrueを返した後にファイルが削除されることがありますが、 fopenの前)。

しかし、エラーをなくすためにエラーを抑制するだけではありません。これらはよく見える。

24
Paweł Hajdan

注:まず、99%のPHP開発者はエラー抑制演算子を使用します(以前はその1つでした)であるため、任意のPHP =これに同意しない開発者。

あなたの意見では、エラーを処理しているのに対して、@ =演算子を使用してPHPのエラー/警告を抑制することは有効ですか?

短い答え:
いいえ!

より長い正解:
すべてを知っているわけではないのでわかりませんが、これまでのところ、それが良い解決策である状況に遭遇したことはありません。

なぜ悪いのか:
PHPを使用して約7年だと思いますが、現在、エラー抑制演算子によって引き起こされる無限のデバッグの苦痛を目にし、避けられない状況に遭遇したことはありません。

問題は、エラーを抑制しているコードが、現在表示されているエラーのみを引き起こす可能性があることです。ただし、抑制された行が依存するコードまたは実行される環境を変更すると、無視しようとしたエラーとはまったく異なるエラーを出力しようとする可能性があります。次に、出力していないエラーをどのように追跡しますか?デバッグ地獄へようこそ!

エラーが抑制されたために2か月ごとに無駄になっていた時間を認識するのに何年もかかりました。ほとんどの場合(ただし排他的ではありません)、これは開発者環境でエラーのないサードパーティのスクリプト/アプリ/ライブラリをインストールした後のものでしたが、PHPまたはサーバー構成の違いまたは通常はすぐにエラーを出力する依存関係がないため、問題が何であるかを警告しますが、開発者がマジック@を追加したときは警告しません。

代替案(状況と望ましい結果に応じて):
認識している実際のエラーを処理して、コードの一部が特定のエラーを引き起こす場合、その特定の状況では実行されないようにします。しかし、私はあなたがこの部分を手に入れ、エンドユーザーがエラーを見るのを心配していたと思います。

通常のエラーの場合、ページを表示しているときに希望どおりに出力されるようにエラーハンドラーを設定できますが、エンドユーザーから隠されてログに記録されるため、ユーザーがトリガーしているエラーがわかります。

致命的なエラーの場合はdisplay_errorsをphp.iniでオフ(エラーハンドラーが引き続きトリガーされる)にし、エラーログを有効にします。開発サーバーとライブサーバー(推奨)がある場合、この手順は開発サーバーで必要ないため、エラーログファイルを調べることなく、これらの致命的なエラーをデバッグできます。 シャットダウン機能を使用したトリック があり、エラーハンドラに致命的なエラーを大量に送信します。

要約:
それを避けてください。それには正当な理由があるかもしれませんが、私はまだそれを見ていません。そのため、その日まで、(@)エラー抑制演算子は悪であると私の意見です。

詳細情報が必要な場合は、PHPマニュアルで Error Control Operatorsページの私のコメント を読むことができます。

116
Gerry

はい、抑制は理にかなっています。

たとえば、fopen()コマンドは、ファイルを開くことができない場合、FALSEを返します。それは問題ありませんが、alsoはPHP警告メッセージを生成します。多くの場合、警告は不要です- 'FALSEを自分で確認します。

実際、 PHPマニュアル は、この場合に@を使用することを具体的に提案しています!

18
Jason Cohen

Fopen()などの関数を使用しているときに警告をスローしたくない場合は、エラーを抑制できますが、例外を使用できます。

try {
    if (($fp = @fopen($filename, "r")) == false) {
        throw new Exception;
    } else {
        do_file_stuff();
    }
} catch (Exception $e) {
    handle_exception();
}
12
dirtside

自分が「@」...を使用することを許可しません。

コードで「@」の使用を発見したら、使用箇所とそれが使用されている関数の周りのdocblockの両方ではっきりと見えるようにコメントを追加します。私もこの種のエラー抑制のために「ゴーストを追いかける」デバッグに噛まれました。見つけたときにその使用法を強調することで、次の人が簡単になりたいと思っています。

ネイティブのPHP関数でエラーが発生し、 '@'が簡単な方法だと思われる場合に独自のコードに例外をスローさせたい場合、代わりに行うことを選択します同じ結果が得られるものの、コードで(再び)明白に明らかな何か:

$orig = error_reporting(); // capture original error level
error_reporting(0);        // suppress all errors
$result = native_func();   // native_func() is expected to return FALSE when it errors
error_reporting($orig);    // restore error reporting to its original level
if (false === $result) { throw new Exception('native_func() failed'); }

それは書くだけのもっと多くのコードです:

$result = @native_func();

しかし、私に続く貧弱なデバッグ魂のために、私は私の抑圧を非常に明白にする必要があります。

7
ashnazg

エラー抑制は、すべての条件を処理できるknowでない限り回避する必要があります。

これは最初に見えるよりもはるかに難しいかもしれません。

本当にすべきなのは、PHPの "error_log"をレポート方法として使用することです。ユーザーがページを表示してエラーを報告することはできません。 (そして、PHPがこれらのエラーを表示しないようにするべきです)

そうすれば、少なくとも、システムで問題が発生しているすべての包括的なレポートを作成できます。

本当にエラーを処理する必要がある場合は、カスタムエラーハンドラーを作成できます

http://php.net/set-error-handler

次に、例外(処理可能)を送信し、奇妙なエラーを管理に報告するために必要なことを行うことができます。

6
Kent Fredric

ほとんどの人は、エラーメッセージの意味を理解していません。
冗談はありません。それらのほとんど。

彼らはエラーメッセージはすべて同じであると考え、「何かがうまくいかない!」と言います。
彼らはそれを読むことを気にしません。
エラーメッセージの最も重要な部分ですが、発生した事実だけでなく、意味もあります。 whatが間違っていることがわかります。エラーメッセージはヘルプ用であり、「非表示にする方法」に煩わされるためのものではありません。問題。これは、初心者のWebプログラミングの世界における最大の誤解の1つです。

したがって、エラーメッセージを吐き出す代わりに、それが言うことをreadする必要があります。 「ファイルが見つかりません」という値は1つだけではありません。数千の異なるエラーが発生する可能性があります:permission deniedsave mode restrictionopen_basedir restrictionなど。それぞれに適切なアクションが必要です。 しかし、あなたがそれをギャグした場合、あなたは何が起こったのか決してわかりません!

OPはエラーを混乱させていますreporting with error handling、それは非常に大きな違いです!
エラー処理はユーザー向けです。ここでは「何かが起こった」で十分です。
エラー報告はプログラマ向けのものですが、プログラマーは必然的に何が起こったかを知る必要があります。

したがって、決してエラーメッセージをギャグしません。 log itプログラマ向け、およびhandle it向け。

5

本当に使用する必要があるのは、eval関数のみです。 evalの問題は、構文エラーが原因で文字列を解析できない場合、evalはfalseを返さず、通常のスクリプトで解析エラーが発生するようにエラーをスローすることです。文字列に格納されているスクリプトが解析可能かどうかを確認するには、次のようなものを使用できます。

$script_ok = @eval('return true; '.$script);

私の知る限り、これが最もエレガントな方法です。

3
Milan Babuškov

@を使用すると、逆効果になる場合があります。私の経験では、php.iniでエラー報告を常にオフにするか、

error_reporting(0);

生産現場で。この方法では、開発中に行をコメントアウトし、デバッグのためにエラーを表示したままにすることができます。

3
Eric Lamb

php.iniの警告とエラーを抑制する方法はありませんか?その場合、フラグを変更するだけでデバッグでき、どの@が問題を隠しているかを発見しようとしません。

3
Enrico Murru

私が使用している場所の1つはソケットコードです。たとえば、タイムアウトを設定している場合、@を含めないと、パケットを取得しないことは有効ですが、警告が表示されます。

$data_len = @socket_recvfrom( $sock, $buffer, 512, 0, $remote_Host, $remote_port )
2
Don Neufeld

今日、少なくとも一時的に@演算子を使用したい場合の良い例である問題に遭遇しました。

長い話を短くすると、エラーログトレースにログオン情報(プレーンテキストのユーザー名とパスワード)が書き込まれていることがわかりました。

ここでは、この問題についてもう少し詳しく説明します。

システムはさまざまなログオンメカニズムを提供することになっているため、ログオンロジックは独自のクラスにあります。サーバーの移行の問題により、エラーが発生しました。そのエラーにより、パスワード情報を含むトレース全体がエラーログにダンプされました! 1つの方法では、ユーザー名とパスワードをパラメーターとして想定していたため、トレースはすべてをエラーログに忠実に書き込みました。

ここでの長期的な修正は、ユーザー名とパスワードを2つのパラメーターとして使用する代わりに、クラスをリファクタリングすることです。たとえば、これら2つの値を含む単一の配列パラメーターを使用します。この問題に取り組む他の方法もありますが、それはまったく別の問題です。

いずれかの方法。トレースメッセージは役立ちますが、この場合はまったく有害です。

トレース出力に気付いたすぐに学んだ教訓:一時的にエラーメッセージを抑制することは、さらなる害を避けるための有用なストップギャップ測定です。

私の意見では、クラス設計が悪いとは思いませんでした。エラー自体は、PDOException(MySQL 5.6から5.7に移行するタイムスタンプの問題)によってトリガーされました。これは、PHPデフォルトをすべてエラーログにダンプしました。

一般に、他のコメントで説明されているすべての理由で@演算子を使用しませんが、この場合、エラーログにより、問題が適切に修正されるまで何かをすばやく行うように説得されました。

1
Herbert Peters

スクリプトを遅くするため、すべてを抑制したくありません。

そして、はい、php.iniとスクリプト内の両方でエラーを削除する方法があります(ただし、ライブ環境にいて、phpからエラーをログに記録する場合にのみこれを行ってください)

<?php
    error_reporting(0);
?>

また、php.iniバージョンのオフの場合は this と読むことができます。

1
Ólafur Waage

カスタムエラー処理関数を使用していて、エラー(おそらく既知のエラー)を抑制したい場合は、このメソッドを使用します。エラーハンドラが設定されている場合、エラーを抑制しないため、このコンテキストでは「@」を使用することはお勧めできません。

3つの関数を記述し、このように呼び出します。

# supress error for this statement
supress_error_start();  
$mail_sent = mail($EmailTo, $Subject, $message,$headers);
supress_error_end(); #Don't forgot to call this to restore error.  

function supress_error_start(){
    set_error_handler('nothing');
    error_reporting(0);
}

function supress_error_end(){
    set_error_handler('my_err_handler');
    error_reporting('Set this to a value of your choice');
}

function nothing(){ #Empty function
}

function my_err_handler('arguments will come here'){
      //Your own error handling routines will come here
}
0
Sumesh