你所不知的 PHP 断言(assert)
PHP 中的断言常用于调试,检查一个表达式或语句是否为 FALSE。本文带你重新认识 PHP
assert()函数的神(Qi)通(Yin)广(Ji)大(Qiao)。本文基于 PHP Version 7.1.28
什么是断言
编写程序时,常会做出一定的假设,那断言就是用来捕获假设的异常,我们也可以认为断言是异常的一种特殊形式。
断言一般用于程序执行结构的判断,不可让断言处理业务流程。用的最多的场景就是单元测试,一般的单元测试框架都采用了断言。
assert(1 == 2);
// 运行结果:
// Warning: assert(): assert(1 == 2) failed in /Users/shocker/Desktop/demo.php on line 25
PHP 中的断言
在 PHP 中,采用 assert() 函数对表达式进行断言。
// PHP 5
assert ( mixed $assertion [, string $description ] ) : bool
// PHP 7
assert ( mixed $assertion [, Throwable $exception ] ) : bool
传统的断言方式 (PHP 5 & 7)
参数 assertion 既支持表达式,也支持表达式字符串(某些特定的场景会用到,比如判断某个字符串表达式是否合法)
如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来执行。assertion 是字符串的优势是当禁用断言时它的开销会更小,并且在断言失败时消息会包含 assertion 表达式。
断言这个功能应该只被用来调试。你应该用于完整性检查时测试条件是否始终应该为 TRUE,来指示某些程序错误,或者检查具体功能的存在(类似扩展函数或特定的系统限制和功能)。
断言不应该用于普通运行时操作,类似输入参数的检查。作为一个经验法则,在断言禁用时你的代码也应该能够正确地运行。
使用示例:
function my_assert_handler($file, $line, $code, $desc)
{
    echo "Assertion Failed:
    File '{$file}'
    Line '{$line}'
    Code '{$code}'
    Desc '{$desc}'
";
}
// 设置回调函数
assert_options(ASSERT_CALLBACK, 'my_assert_handler');
// 让一则断言失败
assert('1 == 2', '1 不可能等于 2');
运行结果:
Assertion Failed:
    File '/Users/shocker/Desktop/demo.php'
    Line '29'
    Code '1 == 2'
    Desc '1 不可能等于 2'
支持异常的断言 (仅 PHP 7)
在 PHP 7 中,assert() 是一个语言结构,允许在不同环境中生效不同的措施,具体可见 zend.assertions 配置。
另外,还支持通过 AssertionError 捕获错误。
使用示例:
assert_options(ASSERT_EXCEPTION, 1); // 在断言失败时产生异常
try {
    // 用 AssertionError 异常替代普通字符串
    assert(true == false, new AssertionError('True is not false!'));
} catch (Throwable $e) {
    echo $e->getMessage();
}
运行结果:
True is not false!
对断言行为进行控制
PHP 支持 assert_options() 函数对断言进行配置,也可用 ini 进行设置
以下配置中,常量标志用于
assert_options()函数进行配置,ini 设置用于ini_set()函数设置,效果一样
| 标志 | INI 设置 | 默认值 | 描述 | 
|---|---|---|---|
| ASSERT_ACTIVE | assert.active | "1" | 启用 assert() 断言 | 
| ASSERT_WARNING | assert.warning | "1" | 为每个失败的断言产生一个 PHP 警告(warning) | 
| ASSERT_BAIL | assert.bail | "0" | 在断言失败时中止执行 | 
| ASSERT_QUIET_EVAL | assert.quiet_eval | "0" | 在断言表达式求值时禁用 error_reporting | 
| ASSERT_CALLBACK | assert.callback | NULL | 断言失败时调用该回调函数 | 
| ASSERT_EXCEPTION | assert.exception | "0" | 在断言失败时产生 AssertionError 异常 (自 PHP 7.0.0 起有效) | 
zend.assertions 是个特殊的配置(PHP >= 7.0.0 支持),控制不同运行环境下断言的行为,仅可用 ini_set() 进行设置。并且,设置了1就不能再设置为-1,反之亦然,其他不受限。
- 1: 编译代码,并执行(开发模式)
 - 0: 编辑代码,但运行时跳过
 - -1: 不编译代码(生产模式)
 
版本的不兼容
PHP >= 5.4.8,description 可作为第四个参数提供给 ASSERT_CALLBACK 模式里的回调函数
在 PHP 5 中,参数 assertion 必须是可执行的字符串,或者运行结果为布尔值的表达式
在 PHP 7 中,参数 assertion 可以是任意表达式,并用其运算结果作为断言的依据
在 PHP 7 中,参数 exception 可以是个 Throwable 对象,用于捕获表达式运行错误或断言结果为失败。(当然 assert.exception 需开启)
PHP >= 7.0.0,支持
zend.assertions、assert.exception相关配置及其特性PHP >= 7.2 版本开始,参数 assertion 不再支持字符串
Deprecated: assert(): Calling assert() with a string argument is deprecated
应用场景
调试输出
先看示例:
assert('1 == 2', '1 不可能等于 2');
运行结果:
Warning: assert(): 1 不可能等于 2: "1 == 2" failed in /Users/shocker/Desktop/demo.php on line 10
类似于:
$expression = 1 == 2;
if (!($expression)) {
    echo "1 不可能等于 2\n";
    var_dump($expression);
    echo __FILE__ . "\n";
}
但是,我们无法得知 $expression 的具体表达式,也无法得知具体的执行行数。
单元测试
function arraySum(array $nums) {
    $sum = 0;
    foreach ($nums as $n) {
        $sum += $n;
    }
    return $sum;
}
assert(arraySum([1, 2, 3]) == 6, 'arraySum() 测试不通过:');
assert(is_numeric(arraySum([1, 2, 3])), 'arraySum() 测试不通过:');
是不是跟我们用 PHPUnit 写单元测试很像
你所不知的 PHP 断言(assert)的更多相关文章
- 你所不知道的setInterval
		
在你所不知道的setTimeout记载了下setTimeout相关,此篇则整理了下setInterval:作为拥有广泛应用场景(定时器,轮播图,动画效果,自动滚动等等),而又充满各种不确定性的这set ...
 - 你所不知道的setTimeout
		
JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务.初始接触它的人都觉得好简单 ...
 - 你真的会玩SQL吗?你所不知道的 数据聚合
		
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
 - 你所不知道的linq(二)
		
上一篇说了from in select的本质,具体参见你所不知道的linq.本篇说下from...in... from... in... select 首先上一段代码,猜猜结果是什么? class P ...
 - 断言(assert)的用法
		
我一直以为assert仅仅是个报错函数,事实上,它居然是个宏,并且作用并非“报错”. 在经过对其进行一定了解之后,对其作用及用法有了一定的了解,assert()的用法像是一种“契约式编程”,在我的理解 ...
 - 你所不知道的SQL Server数据库启动过程,以及启动不起来的各种问题的分析及解决技巧
		
目前SQL Server数据库作为微软一款优秀的RDBMS,其本身启动的时候是很少出问题的,我们在平时用的时候,很少关注起启动过程,或者很少了解其底层运行过程,大部分的过程只关注其内部的表.存储过程. ...
 - 你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)
		
前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...
 - Android中Context详解 ---- 你所不知道的Context
		
转自:http://blog.csdn.net/qinjuning/article/details/7310620Android中Context详解 ---- 你所不知道的Context 大家好, ...
 - C语言中断言ASSERT
		
我一直以为assert仅仅是个报错函数,事实上,它居然是个宏,并且作用并非"报错". 在经过对其进行一定了解之后,对其作用及用法有了一定的了解,assert()的用法像是一种&qu ...
 
随机推荐
- 用Toad for Oracle创建数据库表空间和用户
			
打开Toad, 1,菜单栏Session—>new Connection….打开如下窗口: 2,进入之后,菜单DatebaseàSechema Brower...找到Table Space(表 ...
 - Troubleshooting ORA-30036 - Unable To Extend Undo Tablespace (Doc ID 460481.1)
			
Troubleshooting ORA-30036 - Unable To Extend Undo Tablespace (Doc ID 460481.1) APPLIES TO: Oracle Da ...
 - 记录一下自己在MVC项目中如何防CSRF攻击,直接上代码
			
1.前端的处理: 2.后台 1.)添加过滤器,哪里用放哪里 2.)需要验证的方法上直接添加过滤器即可 大功告成 以下为过滤器代码块 /// <summary>/// ajax中加上Anti ...
 - RAID5的创建(5块磁盘,三块做raid,两块做备份)
			
RAID5的创建(5块磁盘,三块做raid,两块做备份) 第一步:参考我的上一篇博客,用同样的方法添加5块硬盘.地址如下: https://www.cnblogs.com/Feng-L/p/11735 ...
 - 6. Go语言—字符串操作
			
一.字符串支持的转义字符 \r 回车符(返回行首) \n 换行符(直接跳到下一行的同列位置) \t 制表符 \' 单引号 \" 双引号 \\ 反斜杠 \uXXXX Unicode字符码值转义 ...
 - 训练自己数据-xml文件转voc格式
			
首先我们有一堆xml文件 笔者是将mask-rcnn得到的json标注文件转为xml的 批量json转xml方法:https://www.cnblogs.com/bob-jianfeng/p/1112 ...
 - Mybatis环境搭建(二)
			
1. 创建Maven Project,选择war,修改pom.xml <properties> <!-- JDK版本 --> <java.version>1.8&l ...
 - 《为什么说 Prometheus 是足以取代 Zabbix 的监控神器?》
			
为什么说 Prometheus 是足以取代 Zabbix 的监控神器? Kuberneteschina 致力于提供最权威的 Kubernetes 技术.案例与Meetup! 关注他 12 人赞同 ...
 - JavaScript查找两个数组的相同元素和相差元素
			
let intersection = a.filter(v => b.includes(v)) 返回交集数组 let difference = a.concat(b).filter(v => ...
 - TCP的三次握手与四次挥手理解
			
本文经过借鉴书籍资料.他人博客总结出的知识点,欢迎提问 序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生:给字节编上序号后 ...