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.assertionsassert.exception 相关配置及其特性

  • PHP >= 7.2 版本开始,参数 assertion 不再支持字符串

    详见 PHP 7.2.x 中废弃的功能

    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)的更多相关文章

  1. 你所不知道的setInterval

    在你所不知道的setTimeout记载了下setTimeout相关,此篇则整理了下setInterval:作为拥有广泛应用场景(定时器,轮播图,动画效果,自动滚动等等),而又充满各种不确定性的这set ...

  2. 你所不知道的setTimeout

    JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务.初始接触它的人都觉得好简单 ...

  3. 你真的会玩SQL吗?你所不知道的 数据聚合

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  4. 你所不知道的linq(二)

    上一篇说了from in select的本质,具体参见你所不知道的linq.本篇说下from...in... from... in... select 首先上一段代码,猜猜结果是什么? class P ...

  5. 断言(assert)的用法

    我一直以为assert仅仅是个报错函数,事实上,它居然是个宏,并且作用并非“报错”. 在经过对其进行一定了解之后,对其作用及用法有了一定的了解,assert()的用法像是一种“契约式编程”,在我的理解 ...

  6. 你所不知道的SQL Server数据库启动过程,以及启动不起来的各种问题的分析及解决技巧

    目前SQL Server数据库作为微软一款优秀的RDBMS,其本身启动的时候是很少出问题的,我们在平时用的时候,很少关注起启动过程,或者很少了解其底层运行过程,大部分的过程只关注其内部的表.存储过程. ...

  7. 你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)

    前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...

  8. Android中Context详解 ---- 你所不知道的Context

    转自:http://blog.csdn.net/qinjuning/article/details/7310620Android中Context详解 ---- 你所不知道的Context 大家好,  ...

  9. C语言中断言ASSERT

    我一直以为assert仅仅是个报错函数,事实上,它居然是个宏,并且作用并非"报错". 在经过对其进行一定了解之后,对其作用及用法有了一定的了解,assert()的用法像是一种&qu ...

随机推荐

  1. 【原创】CentOS 7 安装解压版mysql5.7

    1.将mysql压缩包解压至 /usr/local 文件夹下,将其改名为mysql #解压 tar -zxf mysql-5.7.27-el7-x86_64.tar.gz -C /usr/local/ ...

  2. [视频教程] 配置vscode的PHP自动补全提示与使用Xdebug进行远程调试debug

    默认下载安装完的vscode并不能准确提示和检测PHP的语法错误,需要手动指定一下本机的PHP程序路径.按下面的操作配置完后就能在文件保存的时候检测语法有无错误.打开文件->首选项->se ...

  3. appium---adb logcat 命令详解

    我们在做app测试的过程中,肯定会遇到需要抓取日志问题,这几天安静也遇到了此问题,后台日志生成的太多了,保存本地了吧,设备多没有这么USB,通过wifi连接又太麻烦,你说这怎么是好?不要着急,我们往下 ...

  4. linux shell脚本命令

    sort命令 sort #按照字典序排序 sort -n #以数值来排序,避免10比2小的情况 sort -k #如果文件有多列,指定排序的列 sort -r #逆序排列 uniq 命令 sort t ...

  5. 【声明式事务】Spring声明式事务实现(三)

    以MyBatis为例. 一.基于注解的声明式事务配置 1. 添加tx名字空间 xmlns:tx="http://www.springframework.org/schema/tx" ...

  6. 剑指Offer-13.调整数组顺序使奇数位于偶数前面(C++/Java)

    题目: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 分析: 这道题做法有很 ...

  7. 浅谈C++ STL stack 容器

    浅谈C++ STL stack 容器 本篇随笔简单介绍一下\(C++STL\)中\(stack\)容器的使用方法和常见的使用技巧. stack容器的概念 \(stack\)在英文中是栈的意思.栈是一种 ...

  8. [mybatis] sql语句无错误,但是执行多条sql语句时,抛出java.sql.SQLSyntaxErrorException

    错误内容 org.springframework.jdbc.BadSqlGrammarException: ### Error updating database. Cause: java.sql.S ...

  9. Java 发红包

    使用Java实现发红包的功能. 结构: package redPocket User.java Manager.java Member.java Demo.java 思路: Manager和Membe ...

  10. MySQL实战45讲学习笔记:第三十六讲

    一.引子 今天是大年三十,在开始我们今天的学习之前,我要先和你道一声春节快乐! 在上一篇文章中,我们在优化 join 查询的时候使用到了临时表.当时,我们是这么用的: create temporary ...