web-dev-qa-db-ja.com

PHPコードでassertを使用すべきですか?

同僚がifステートメントを使用して例外をスローする場所で、ライブラリ内に assert コマンドを数回追加しました。 (私はこれまでアサートのことを聞いたことがありませんでした。)以下は彼がそれをどのように使用したかの例です:

assert('isset($this->records); /* Records must be set before this is called. */');

私がやっただろう:

if (!isset($this->records)) {
    throw new Exception('Records must be set before this is called');
}

the PHP assert on docs を読むと、assertがアクティブであることを確認し、assertを使用する前にハンドラーを追加することをお勧めしているようです。彼がこれをやった場所。

だから、私の質問は、上記を考えるとアサートを使用することは良いアイデアであり、ifと例外の代わりにそれをより頻繁に使用する必要がありますか?

もう1つの注意点として、これらのライブラリは、私たちが所属していないプロジェクトも含めて、さまざまなプロジェクトやサーバーで使用する予定です(ライブラリはオープンソースです)。これはassertの使用に違いをもたらしますか?

83
Darryl Hein

ほとんどの言語(漠然と知っているすべての言語)に適用される経験則は、assertを使用して条件がalways trueであるのに対し、ifは、失敗することが考えられる場合に適切です。

この場合、assertは指定されたメソッドが呼び出される前にalwaysに設定する必要があるため、recordsが適切であると言えます(状況に対する私の弱い理解に基づく)。 。したがって、レコードの設定に失敗すると、実行時の状態ではなく、プログラムのバグになります。ここで、assertは、(適切なテストで)assertで保護されているコードがrecordsが設定されています。

assertとは対照的にifを使用する利点は、assertを本番コードで一般的にオフにできるため、オーバーヘッドが削減されることです。 ifで最適に処理される状況は、実稼働システムでの実行中に発生する可能性があるため、それらをオフにできないことで何も失われません。

77
aaronasterling

アサートは「パワーコメント」と考えてください。次のようなコメントではなく:

// Note to developers: the parameter "a" should always be a number!!!

使用する:

assert('is_numeric(a) /* The parameter "a" should always be a number. */');

意味はまったく同じで、まったく同じ視聴者を対象としていますが、最初のコメントは簡単に忘れたり無視したりできます(感嘆符の数に関係なく)。また、開発中は常にマシンテストが行​​われます。コードおよび作業習慣で適切なアサート処理を設定しても無視されません。

このように、アサートはif(error)...と例外とはまったく異なる概念であり、共存できます。

はい、コードにコメントする必要があります。また、可能であれば、「パワーコメント」(アサート)を使用する必要があります。

25
DaveWalley

開発戦略に完全に依存します。ほとんどの開発者はassert()を知らず、ダウンストリームユニットテストを使用します。ただし、予防的で組み込みのテストスキームが有利な場合があります。

assertは有効または無効にできるため便利です。そのようなアサーションハンドラが定義されていない場合、パフォーマンスは低下しません。同僚には持っていないので、開発環境で一時的に有効にするコードを作成する必要があります(E_NOTICE/E_WARNINGsがオンの場合は、アサーションハンドラーもオンにしてください)。私は、コードが変数の型を混ぜることができない場所で時々それを使用します-私は通常、弱い型付けのPHPで厳密な型付けを行いませんが、ランダムなユースケースがあります:

 function xyz($a, $b) {
     assert(is_string($a));
     assert(is_array($b));

たとえば、型指定子string $a, array $bの欠如を補います。 PHP5.4はそれらをサポートしますが、チェックはしません。

16
mario

アサートは、ifや例外などの通常のフロー制御の代替ではありません。開発中のデバッグにのみ使用されるためです。

7
Mark Snidovich

PHPの7より前のアサートに関する重要な注意点。アサート構造を持つ他の言語とは異なり、PHPはアサート文を完全にスローしない-関数として処理します(debug_backtrace()を実行します)アサーションによって呼び出される関数)。アサーションをオフにすると、エンジンで何もしないように関数をホットワイヤするように見えます。 PHP 7は、zend.assertionsを通常の値である1(オン)または-1(オフ)の代わりに0に設定することで、この動作をエミュレートすることができます。

この問題は、assertが引数を取る場合に発生しますが、引数が文字列でない場合、assertがオンかオフかにかかわらず、assertは式の結果を取得します。これは、次のコードブロックで確認できます。

<?php
  function foo($a) { 
    echo $a . "\n"; 
    return TRUE;
  }
  assert_options(ASSERT_ACTIVE, FALSE);

  assert( foo('You will see me.'));
  assert('foo(\'You will not see me.\')');

  assert_options(ASSERT_ACTIVE, TRUE);

  assert( foo('Now you will see'));
  assert('foo(\'both of us.\')');

Assertの意図を考えると、これはバグであり、assertがPHP 4で導入されて以来、言語内に存在するため、長い間存在していました。

Assertに渡された文字列は、それに伴うすべてのパフォーマンスへの影響と危険を伴い評価されますが、assertステートメントをPHPで動作するようにする唯一の方法です(この動作はPHP 7.2)。

編集:PHP 7および7.2での変更に注意するために上記を変更

5
Michael Morris

アサートはデバッグに役立つため、開発でのみ使用してください。そのため、Webサイトの開発にそれらを使用できますが、ライブWebサイトには例外を使用する必要があります。

4
Kyle

いいえ、同僚が汎用エラーハンドラとして使用するべきではありません。マニュアルによると:

アサーションは、デバッグ機能としてのみ使用する必要があります。常にTRUEである必要がある条件をテストし、そうでない場合はプログラミングエラーを示す健全性チェック、または拡張機能や特定のシステム制限や機能などの特定の機能の有無を確認するための健全性チェックに使用できます。

アサーションは、入力パラメーターのチェックなどの通常のランタイム操作には使用しないでください。経験則として、アサーションチェックが有効になっていない場合、コードは常に正しく動作する必要があります。

自動化されたテストスイートに精通している場合、一般に「アサート」動詞を使用して、メソッドまたは関数の出力を検証します。例えば:

function add($a, $b) {
    return $a + $b;
}

assert(add(2,2) == 5, 'Two and two is four, dummy!');
assert(is_numeric(add(2,2)), 'Output of this function to only return numeric values.');

同僚が汎用エラーハンドラとして、この場合は入力チェックとして使用しないでください。ライブラリの一部のユーザーがレコードフィールドを設定しない可能性があるようです。

3
Dean Or

あなたの同僚は、実際に適用しようとしています 契約による設計 (DbC)Eiffel言語から、本に基づいています:オブジェクト指向ソフトウェア構築、第2版。

アサーションは、彼が使用したとおり、Hoare LogicまたはHoare Tripleの{P}部分になります。{P} C {Q}。ここで、{P}は前提条件assert(ion)sであり、{Q}は事後条件のアサート。

PHPバグがあります。バグのあるコードは使いたくありません。本当に欲しいのはPHPは、アサートのバグを修正します。修正するまで、アサートを使用できますが、現在のバグのある状態に注意して使用してください。

さらに、アサート機能にバグがある場合は、実稼働コードでは使用しないことをお勧めします。それでも、必要に応じて開発およびテストコードで使用することをお勧めします。

最後に、契約による設計の研究を行う場合、オブジェクト指向の古典的な継承を考慮してブールアサーションを使用すると結果が生じることがわかります。つまり、前提条件を弱めたり、事後条件を弱めたりしてはいけません。そうすることは、相互作用している多相的な子孫オブジェクトにとって危険です。あなたがそれが何を意味するかを理解するまで、私はそれを放っておこう!

さらに、PHP=のメーカーは、契約による設計の包括的な研究を行い、それをPHPできるだけ早く!上記の回答に記載されている問題を処理するDbC対応のコンパイラ/インタープリターを使用することの利点:

  1. 適切に実装された設計対応のコンパイラは、(できれば)バグのないものになります(現在のPHP assert)とは異なります)。
  2. 適切に実装された設計対応のコンパイラは、問題に頭を悩ませる代わりに、ポリモーフィックなアサーションロジック管理のニュアンスを処理します!

注:前提条件を強化したり、事後条件を弱めたりするために使用した場合、if-ステートメントをアサート(前提条件)の代わりとして使用しても、悲惨な結果になります。それが何を意味するのかを理解するには、契約によって設計を学習する必要があります! :-)

幸せな勉強と学習。

3
Larry