©
本文档使用
php.cn手册 发布
(PHP 4, PHP 5, PHP 7)
assert — 检查一个断言是否为 FALSE
PHP 5
$assertion
[, string $description
] )PHP 7
$assertion
[, Throwable $exception
] ) assert() 会检查指定的
assertion
并在结果为 FALSE
时采取适当的行动。
如果 assertion
是字符串,它将会被 assert() 当做 PHP 代码来执行。
assertion
是字符串的优势是当禁用断言时它的开销会更小,并且在断言失败时消息会包含 assertion
表达式。
这意味着如果你传入了 boolean 的条件作为 assertion
,这个条件将不会显示为断言函数的参数;在调用你定义的 assert_options() 处理函数时,条件会转换为字符串,而布尔值 FALSE
会被转换成空字符串。
断言这个功能应该只被用来调试。
你应该用于完整性检查时测试条件是否始终应该为 TRUE
,来指示某些程序错误,或者检查具体功能的存在(类似扩展函数或特定的系统限制和功能)。
断言不应该用于普通运行时操作,类似输入参数的检查。 作为一个经验法则,在断言禁用时你的代码也应该能够正确地运行。
assert() 的行为可以通过 assert_options() 来配置,或者手册页面上描述的 .ini 设置。
assert_options() ASSERT_CALLBACK
配置指令允许设置回调函数来处理失败的断言。
assert() 回调函数在构建自动测试套件的时候尤其有用,因为它们允许你简易地捕获传入断言的代码,并包含断言的位置信息。 当信息能够被其他方法捕获,使用断言可以让它更快更方便!
回调函数应该接受三个参数。
第一个参数包括了断言失败所在的文件。
第二个参数包含了断言失败所在的行号,第三个参数包含了失败的表达式(如有任意 — 字面值例如 1 或者 "two" 将不会传递到这个参数)。
PHP 5.4.8 及更高版本的用户也可以提供第四个可选参数,如果设置了,用于将 description
指定到 assert() 。
assert() is a language construct in PHP 7, allowing for the definition of expectations: assertions that take effect in development and testing environments, but are optimised away to have zero cost in production.
While assert_options() can still be used to control behaviour as described above for backward compatibility reasons, PHP 7 only code should use the two new configuration directives to control the behaviour of assert() and not call assert_options() .
Directive | Default value | Possible values |
---|---|---|
zend.assertions | 1 |
|
assert.exception | 0 |
|
assertion
断言。In PHP 5, this must be either a string to be evaluated or a boolean to be tested. In PHP 7, this may also be any expression that returns a value, which will be executed and the result used to indicate whether the assertion succeeded or failed.
description
如果 assertion
失败了,选项 description 将会包括在失败信息里。
exception
In PHP 7, the second parameter can be a Throwable object instead of a descriptive string , in which case this is the object that will be thrown if the assertion fails and the assert.exception configuration directive is enabled.
assertion 是 false 则返回 FALSE
,否则是 TRUE
。
版本 | 说明 |
---|---|
7.0.0 | assert() is now a language construct and not a
function. assertion() can now be an expression.
The second parameter is now interpreted either as an
exception (if a
Throwable object is given), or as the
description supported from PHP 5.4.8 onwards.
|
5.4.8 |
增加了参数 description 。
description 现在也作为第四个参数提供给 ASSERT_CALLBACK 模式里的回调函数。
|
Example #1 使用自定义处理程序处理失败的断言
<?php
// 激活断言,并设置它为 quiet
assert_options ( ASSERT_ACTIVE , 1 );
assert_options ( ASSERT_WARNING , 0 );
assert_options ( ASSERT_QUIET_EVAL , 1 );
//创建处理函数
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' );
// 让一则断言失败
assert ( 'mysql_query("")' );
?>
Example #2 使用自定义处理器打印描述信息
<?php
// 激活断言,并设置它为 quiet
assert_options ( ASSERT_ACTIVE , 1 );
assert_options ( ASSERT_WARNING , 0 );
assert_options ( ASSERT_QUIET_EVAL , 1 );
//创建处理函数
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' );
// Make an assertion that should fail
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
Example #3 Expectations without a custom exception
<?php
assert ( true == false );
echo 'Hi!' ;
?>
With zend.assertions set to 0, the above example will output:
Hi!
With zend.assertions set to 1 and assert.exception set to 0, the above example will output:
Warning: assert(): assert(true == false) failed in - on line 2 Hi!
With zend.assertions set to 1 and assert.exception set to 1, the above example will output:
Fatal error: Uncaught AssertionError: assert(true == false) in -:2 Stack trace: #0 -(2): assert(false, 'assert(true == ...') #1 {main} thrown in - on line 2
Example #4 Expectations with a custom exception
<?php
class CustomError extends AssertionError {}
assert ( true == false , new CustomError ( 'True is not false!' ));
echo 'Hi!' ;
?>
With zend.assertions set to 0, the above example will output:
Hi!
With zend.assertions set to 1 and assert.exception set to 0, the above example will output:
Warning: assert(): CustomError: True is not false! in -:4 Stack trace: #0 {main} failed in - on line 4 Hi!
With zend.assertions set to 1 and assert.exception set to 1, the above example will output:
Fatal error: Uncaught CustomError: True is not false! in -:4 Stack trace: #0 {main} thrown in - on line 4
[#1] fabiano dot fa04 at gmail dot com [2013-10-09 17:40:08]
You can also use a function instead a string description as the second parameter.
<?php
function assertIsFalse(){
echo "Hey, this assert is false and I'm a function.";
}
$foo = "foo";
$bar = $foo;
$foo = "bar";
assert( $foo == $bar, assertIsFalse() );
?>
The result would be:
Hey, this assert is false and I'm a function.
[#2] office dot stojmenovic at gmail dot com [2013-09-20 00:35:35]
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);
?>
[#3] devoto13 at gmail dot com [2013-07-03 10:29:34]
"If you would like to compare with === or !== you need to add '(string)' before string numbers. Or wrap them with quotes."
Do not use this aproach, because it would not work, look at http://php.net/manual/en/function.var-export.php .
[#4] uramihsayibok, gmail, com [2010-06-20 13:48:22]
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)
[#5] hodgman at ali dot com dot au [2008-07-28 21:19:43]
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.
[#6] Krzysztof 'ChanibaL' Bociurko [2007-10-01 18:13:06]
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...)
[#7] mail<at>aaron-mueller.de [2006-09-13 10:51:05]
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);
?>
[#8] gk at proliberty dot com [2005-08-26 19:35:54]
If you expect your code to be able to work well with other code, then you should not make any assumptions about the current state of assert_options() flags, prior to calling assert(): other code may disable ASSERT_ACTIVE, without you knowing it - this would render assert() useless!
To avoid this, ALWAYS set assert_options() IMMEDIATELY before calling assert(), per the C++ paradigm for assertion usage:
In one C++ source file, you can define and undefine NDEBUG multiple times, each time followed by #include <cassert>, to enable or disable the assert macro multiple times in the same source file.
Here is how I workaround this issue in my PHP code:
<?php
//////////////////////////////////////////////////////////////////////
/// phpxAssertHandler_f
//////////////////////////////////////////////////////////////////////
/**
* @desc Handler which also sets up assert options if not being called as handler
Always fatal when assertion fails
Always make sure assertion is enabled
Cannot depend on other code not using assert or using its own assert handler!
USAGE:
// customize error level of assertion (php assert_options() only allows E_WARNING or nothing at all):
phpxAssertHandler_f(E_USER_NOTICE);
// control assertion active state: not dependent on anything another piece of code might do with ASSERT_ACTIVE
$GLOBALS['MY_ASSERT_ACTIVE']=false;
phpxAssertHandler_f(E_USER_NOTICE,$GLOBALS['MY_ASSERT_ACTIVE']);
// use alternate assertion callback function:
// NOTE: pass null as custom options parameter to use default options
// NOTE: pass no values for assert options parameter array elements to use default options
$GLOBALS['MY_ASSERT_ACTIVE']=false;
$GLOBALS['MY_ASSERT_CALLBACK']='myAssertCallback';
phpxAssertHandler_f(
null,
array(
0=>$GLOBALS['MY_ASSERT_ACTIVE'],
3=>$GLOBALS['MY_ASSERT_CALLBACK'],
)
);
* @param mixed = file or options
* @param line
* @param code
* @return void
*/
function phpxAssertHandler_f($file_or_custom_options=null, $line_or_assert_options=null, $code=null){
static $custom_options;
$debug = false;
if (is_null($code)){
// set default assert_options
$assert_options[]=1;//ASSERT_ACTIVE
$assert_options[]=0;//ASSERT_WARNING -
$assert_options[]=0;//ASSERT_QUIET_EVAL
$assert_options[]=__FUNCTION__;//ASSERT_CALLBACK
// set default custom_options
$custom_options[]=E_USER_ERROR;// error level
if (!is_null($line_or_assert_options)){
// assert_options are passed in
if (!is_array($line_or_assert_options)){
$line_or_assert_options=array($line_or_assert_options);
}
foreach ($line_or_assert_options as $i=>$assert_option){
if ($assert_option===true) $assert_option=1;
if ($assert_option===false) $assert_option=0;
$assert_options[$i]=$assert_option;
if($debug) echo ("assert_options[$i]=$assert_option\n");
}
}
if (!is_null($file_or_custom_options)){
// custom_options are passed in
if (!is_array($file_or_custom_options)){
$file_or_custom_options=array($file_or_custom_options);
}
foreach ($file_or_custom_options as $i=>$custom_option){
if ($custom_option===true) $custom_option=1;
if ($custom_option===false) $custom_option=0;
$custom_options[$i]=$custom_option;
if($debug) echo ("custom_options[$i]=$custom_option\n");
}
}
// set assert options
@assert_options (ASSERT_ACTIVE, $assert_options[0]);
@assert_options (ASSERT_WARNING, $assert_options[1]);
@assert_options (ASSERT_QUIET_EVAL, $assert_options[2]);
@assert_options (ASSERT_CALLBACK, $assert_options[3]);
} else {
// we are acting as a callback function
$file = $file_or_custom_options;
$line = $line_or_assert_options;
$msg="ASSERTION FAILED: $code";
phpxErrorHandler_f ($custom_options[0],$msg,$file,$line);
}
}//phpxAssertHandler_f()
?>