PHP 7.2.0 Beta 3 Released

assert

(PHP 4, PHP 5, PHP 7)

assertassertion が FALSE であるかどうかを調べる

説明

PHP 5 および PHP 7

bool assert ( mixed $assertion [, string $description ] )

PHP 7

bool assert ( mixed $assertion [, Throwable $exception ] )

assert() は、指定した assertion を調べて、結果が FALSE の場合に適切な動作をします。

従来のアサーション (PHP 5 および 7)

assertion が文字列として指定された場合、 assert()によりPHPコードとして評価されます。 もし論理型の条件を assertion として渡した場合、 assert_options() 関数で定義したであろう アサーション関数への引数として表示されません。 その条件はハンドラ関数をコールする前に文字列に変換され、論理型の FALSE は空文字列に変換されます。

assertion は、デバッグ目的にのみ使用するべきです。 assertion を常にTRUEとなる条件を調べる不具合診断に使用し、TRUE でない場合に何らかのプログラミングエラーを示したり、extension 関数または特定のシステム制限や機能といった、 特定の機能の存在をチェックするために使用することが可能です。

assersion は、入力パラメータのチェックのような通常の実行動作に 使用するべきではありません。一般的には、assertion のチェックを無効にしても そのコードが正常に動作しなければなりません。

assert() の動作は、 assert_options() またはマニュアルの関数の部分 に記述された .ini の設定により設定することが可能です。

関数 assert_options()ASSERT_CALLBACK 設定ディレクティブにより失敗した assertion を処理するコールバック関数を設定することが可能です。

assert() のコールバックは、assertion が発生した場所に関する情報と共に assertion に渡されたコードを容易にキャプチャーできるため、 特に自動テストセットを構築する際に便利です。 この情報は他の手法でもキャプチャー可能ですが、assertion を使用することにより、より簡単かつ容易に行なうことが可能です!

コールバック関数は、3つの引数を受ける必要があります。最初の引数は、 assertionが失敗したファイルが含まれます。2番目の引数には、 assertionが失敗した行が含まれ、3番目の引数には失敗した式が含まれます (もしある場合のみ。1 または "two" のようなリテラルの値は、 この引数に渡されません)。 PHP 5.4.8 以降では、オプションの4番目の引数を指定できます。これを設定すると、 descriptionassert() に渡せるようになります。

Expectation (PHP 7 のみ)

assert() は PHP 7 で言語構造となり、expectation の定義を満たすようになりました。 すなわち、開発環境やテスト環境では有効であるが、運用環境では除去されて、まったくコストのかからないアサーションということです。

下位互換性を保つために、assert_options() でこれらの挙動を制御することもできますが、 PHP 7 以降でしか使わないコードでは、新たに導入された二つの設定ディレクティブを使って assert() の挙動を制御しましょう。 そして assert_options() は使わないようにしましょう。

PHP 7 における assert() 用の設定ディレクティブ
ディレクティブ デフォルト値 取り得る値
zend.assertions 1
  • 1: コードを生成して実行する (開発モード)
  • 0: コードを生成するが、実行時には読み飛ばす
  • -1: コードを生成しない (運用モード)
assert.exception 0
  • 1: アサーションに失敗した場合には、 exception で指定したオブジェクトをスローするか、 exception を指定していない場合は AssertionError オブジェクトをスローします。
  • 0: 先述の Throwable を使ったり生成したりしますが、 そのオブジェクト上で警告を生成するだけであり、スローしません (PHP 5 と互換性のある挙動です)。

パラメータ

assertion

アサーション。 PHP 5 では、評価対象の文字列か、あるいは boolean 値しか指定できませんでした。 PHP 7 ではそれ以外にも、値を返すあらゆる式を指定できます。 この式を実行した結果を用いて、アサーションに成功したか否かを判断します。

警告

Using string as the assertion is DEPRECATED as of PHP 7.2.

description

オプションの説明で、 assertion が失敗したときのメッセージにこれを含めます。

exception

PHP 7 では、第二パラメータに、文字列だけではなく Throwable オブジェクトを指定できるようになりました。 これを指定した場合は、 assert.exception が有効で かつアサーションに失敗した場合に、そのオブジェクトをスローします。

返り値

アサーションが false となった場合に FALSE、それ以外の場合に TRUE を返します。

変更履歴

バージョン 説明
7.2.0 Usage of a string as the assertion became deprecated. It now emits an E_DEPRECATED notice when both assert.active and zend.assertions are set to 1.
7.0.0 assert() が言語構造となり、関数ではなくなりました。 assertion に式を指定できるようになりました。 第二パラメータは、 exception (Throwable オブジェクトを渡した場合) あるいは description (PHP 5.4.8 以降でサポートされていたもの) のいずれかであると解釈されるようになりました。
5.4.8 description パラメータが追加されました。 description はまた、 ASSERT_CALLBACK モードのコールバック関数の4番目の引数にも指定できるようになりました。

従来のアサーション (PHP 5 および 7)

例1 失敗した assertion をカスタムハンドラで処理する

<?php
// assertを有効にし、出力を抑制する
assert_options(ASSERT_ACTIVE1);
assert_options(ASSERT_WARNING0);
assert_options(ASSERT_QUIET_EVAL1);

// ハンドラ関数を作成する
function my_assert_handler($file$line$code)
{
    echo 
"<hr>Assertion Failed:
        File '
$file'<br />
        Line '
$line'<br />
        Code '
$code'<br /><hr />";
}

// コールバックを設定する
assert_options(ASSERT_CALLBACK'my_assert_handler');

// 失敗するassertionを作成
assert('mysql_query("")');
?>

例2 カスタムハンドラを使った説明の表示

<?php
// assertを有効にし、出力を抑制する
assert_options(ASSERT_ACTIVE1);
assert_options(ASSERT_WARNING0);
assert_options(ASSERT_QUIET_EVAL1);

// ハンドラ関数を作成する
function my_assert_handler($file$line$code$desc null)
{
    echo 
"Assertion failed at $file:$line$code";
    if (
$desc) {
        echo 
": $desc";
    }
    echo 
"\n";
}

// コールバックを設定する
assert_options(ASSERT_CALLBACK'my_assert_handler');

// 失敗するassertionを作成
assert('2 < 1');
assert('2 < 1''Two is less than one');
?>

上の例の出力は以下となります。

 Assertion failed at test.php:21: 2 < 1
 Assertion failed at test.php:22: 2 < 1: Two is less than one
 

Expectation (PHP 7 のみ)

例3 自作の例外を指定しない expectation

<?php
assert
(true == false);
echo 
'Hi!';
?>

zend.assertions が 0 の場合は、上の例の結果は次のようになります。

Hi!

zend.assertions が 1、かつ assert.exception が 0 の場合は、上の例の結果は次のようになります。

Warning: assert(): assert(true == false) failed in - on line 2
Hi!

zend.assertions が 1、かつ assert.exception が 1 の場合は、上の例の結果は次のようになります。

Fatal error: Uncaught AssertionError: assert(true == false) in -:2
Stack trace:
#0 -(2): assert(false, 'assert(true == ...')
#1 {main}
  thrown in - on line 2

例4 自作の例外を用いた expectation

<?php
class CustomError extends AssertionError {}

assert(true == false, new CustomError('True is not false!'));
echo 
'Hi!';
?>

zend.assertions が 0 の場合は、上の例の結果は次のようになります。

Hi!

zend.assertions が 1、かつ assert.exception が 0 の場合は、上の例の結果は次のようになります。

Warning: assert(): CustomError: True is not false! in -:4
Stack trace:
#0 {main} failed in - on line 4
Hi!

zend.assertions が 1、かつ assert.exception が 1 の場合は、上の例の結果は次のようになります。

Fatal error: Uncaught CustomError: True is not false! in -:4
Stack trace:
#0 {main}
  thrown in - on line 4

参考

add a note add a note

User Contributed Notes 6 notes

up
4
hodgman at ali dot com dot au
9 years ago
As noted on Wikipedia - "assertions are primarily a development tool, they are often disabled when a program is released to the public." and "Assertions should be used to document logically impossible situations and discover programming errors— if the 'impossible' occurs, then something fundamental is clearly wrong. This is distinct from error handling: most error conditions are possible, although some may be extremely unlikely to occur in practice. Using assertions as a general-purpose error handling mechanism is usually unwise: assertions do not allow for graceful recovery from errors, and an assertion failure will often halt the program's execution abruptly. Assertions also do not display a user-friendly error message."

This means that the advice given by "gk at proliberty dot com" to force assertions to be enabled, even when they have been disabled manually, goes against best practices of only using them as a development tool.
up
2
uramihsayibok, gmail, com
7 years ago
There's a nice advantage to giving assert() some code to execute, as a string, rather than a simple true/false value: commenting.

<?php

assert
('is_int($int) /* $int parameter must be an int, not just numeric */');

// and my personal favorite
assert('false /* not yet implemented */');

?>

The comment will show up in the output (or in your assertion handler) and doesn't require someone debugging to go through your code trying to figure out why the assertion happened. That's no excuse to not comment your code, of course.

You need to use a block comment (/*...*/) because a line comment (//...) creates an "unexpected $end" parse error in the evaluated code. Bug? Could be.
(You can get around it with "false // not yet implemented\n" but that screws up the message)
up
1
mail<at>aaron-mueller.de
10 years ago
Here is a simple demonstration of Design By Contract with PHP

<?php

assert_options
(ASSERT_ACTIVE, 1);
assert_options(ASSERT_WARNING, 0);
assert_options(ASSERT_BAIL, 1);
assert_options(ASSERT_CALLBACK, 'dcb_callback');

function
dcb_callback($script, $line, $message) {
    echo
"<h1>Condition failed!</h1><br />
        Script: <strong>
$script</strong><br />
        Line: <strong>
$line</strong><br />
        Condition: <br /><pre>
$message</pre>";
}

// Parameters
$a = 5;
$b = 'Simple DCB with PHP';

// Pre-Condition
assert('
    is_integer($a) &&
    ($a > 0) &&
    ($a < 20) &&
   
    is_string($b) &&
    (strlen($b) > 5);
'
);

// Function
function combine($a, $b) {
    return
"Kombined: " . $b . $a;
}

$result = combine($a, $b);

// Post-Condition
assert('
    is_string($result) &&
    (strlen($result) > 0);
'
);

// All right, the Function works fine
var_dump($result);

?>
up
1
Krzysztof &#39;ChanibaL&#39; Bociurko
9 years ago
Note that func_get_args() should be used carefully and never in a string! For example:

<?php
function asserted_normal($a, $b) {
   
assert(var_dump(func_get_args()));
    }
function
asserted_string($a, $b) {
   
assert('var_dump(func_get_args())');
    }
?>

<?php asserted_normal(1,2) ?> prints
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}

but <?php asserted_string(3,4) ?> prints
array(1) {
  [0]=>
  string(25) "var_dump(func_get_args())"
}

This is because of that the string passed to assert() is being evaled inside assert, and not your function. Also, note that this works correctly, because of the eval scope:

<?php
function asserted_evaled_string($a, $b) {
   
assert(eval('var_dump(func_get_args())'));
    }
asserted_evaled_string(5,6);
?>
array(2) {
  [0]=>
  int(5)
  [1]=>
  int(6)
}

(oh, and for simplicity's sake the evaled code doesn't return true, so  don't worry that it fails assertion...)
up
0
Ben
11 months ago
if there was no 'warning' message when assertion failed (FALSE), try reset the error handler:
<?php
set_error_handler
( null );
up
-2
office dot stojmenovic at gmail dot com
3 years ago
Example from Ikac Framework how they use assert()

<?php

   
/**
     * Set Assertion Debug
     *
     * This method will check the given assertion and take appropriate -
     * action if its result is FALSE.
     *
     * This file is part of Ikac Framework.
     *
     * @package Ikac Framework
     * @author Ivan Stojmenovic Ikac <contact.@stojmenovic.info>
     *
     * @param mixed $assertion  The assertion.
     * @param mixed $callback Callback to call on failed assertions
     * @param array $options  Set the various control options or just query their current settings.
     * @param string $description  An optional description that will be included in the failure message if the assertion fails.
     */
   
public function setAssertionDebug($assertion, $callback, array $options, $description = null)
    {
        if (
is_array($options)) {
            foreach (
$options AS $option => $value) {
               
assert_options($option, $value);
            }
        }
        if (
$callback) {
           
assert_options(ASSERT_CALLBACK, $callback);
        }
       
        return
assert($assertion, $description);
    }
   
?>

How to use:

<?php
     
use Ikac\Component\SystemBehaviour\OptionsInfo;

     
$system = new OptionsInfo();

     
$option = array(ASSERT_ACTIVE => 1,ASSERT_WARNING => 0,ASSERT_QUIET_EVAL => 1);

    
$system->setAssertionDebug('2<1', function(){
            echo
"Assertion failed";
     },
$option);

?>
To Top