PHP语法高级篇(五):回调函数与异常处理

在 PHP 编程中,回调函数与异常处理是提升代码灵活性与健壮性的关键技术。回调函数能极大增强代码的复用性与扩展性;而异常处理则帮助开发者捕获并妥善处理运行时错误,避免程序意外崩溃。本篇文章将记录过回调函数与异常处理的学习过程。


一、回调函数

回调函数(通常简称为"回调")是一个作为参数传递给另一个函数的函数。函数是以 string 形式传递的。可以使用任何内置或用户自定义函数(从 PHP 7 版本开始,回调参数也接受匿名函数),但除了语言结构,例如:array(),echo,empty(),eval(),exit(),isset(),list(),print 或 unset()。

示例 将回调函数传递给 PHP 的 array_map() 函数,将数组中每个字符串转换为大写

php 复制代码
// array_map:为数组的每个元素应用回调函数

// 回调函数,将数组中每个字符串转换为大写
function my_callback($item) {
    return strtoupper($item);
}

$strings = ["apple", "orange", "banana"];
$upper_strings = array_map('my_callback', $strings);
print_r($upper_strings);

示例 从用户定义的函数中运行回调函数

php 复制代码
// 回调函数
function my_callback() {
    echo 'Hello World!';
}

// 自定义函数,接受回调函数
function custom($callback) {
    $callback();
}

// 调用自定义函数 custom(),将回调函数 my_callback() 作为参数传入
custom("my_callback");

二、异常处理

PHP 有一个和其他语言相似的异常模型。在 PHP 里可以 throw 并捕获(catch)异常。为了捕获潜在的异常,代码会包含在 try 块里。每个 try 都必须至少有一个相应的 catch 或 finally 块。

如果抛出异常的函数作用域内没有 catch 块,异常会沿调用栈"向上冒泡",直到找到匹配的 catch 块。沿途会执行所有遇到的 finally 块。在没有设置全局异常处理程序时,如果调用栈向上都没有遇到匹配的 catch,程序会抛出 fatal 错误并终止。

示例 抛出一个异常

php 复制代码
function divide($dividend, $divisor) {
    if($divisor == 0) {
        // throw 语句允许用户定义的函数或方法抛出异常
        throw new Exception("除数不能为0");
    }
    return $dividend / $divisor;
}

echo divide(1, 0);

上述示例输出:

异常对象(Exception)包含有关函数遇到的错误或意外行为的信息。

语法

php 复制代码
new Exception(message, code, previous)

参数

|----------|--------------------------------------------|
| message | 可选。描述为何抛出异常的字符串。 |
| code | 可选。整数,可用于轻松区分同一类型的不同异常。 |
| previous | 可选。如果此异常是在另一个异常的 catch 块中抛出的,建议将此异常传递给此参数。 |

当捕获异常时,下表显示了一些可用于获取有关异常信息的方法:

|---------------|-------------------------------------------|
| 方法 | 描述 |
| getMessage() | 返回描述为何抛出异常的字符串。 |
| getPrevious() | 如果此异常是由另一个异常触发的,此方法返回前一个异常。如果不是,则返回 null。 |
| getCode() | 返回异常代码。 |
| getFile() | 返回抛出异常的文件的完整路径。 |
| getLine() | 返回抛出异常的代码行的行号。 |

1、try...catch 语句

catch 定义了处理抛出异常的方式。 catch 块定义了它能处理的异常/错误的类型,并可以选择将异常赋值到变量中。如果遇到抛出对象的类型匹配了首个 catch 块的异常或错误,将会处理该对象。

可用多个 catch 捕获不同的异常类。正常情况下(try 代码块里没有抛出异常)会在最后一个定义的 catch 后面继续执行。 catch 代码块里也可以 throw 或者重新抛出异常。不抛出的话,会在触发的 catch 后面继续执行。

当 PHP 抛出一个异常时,将不会执行后续的代码语句,并会尝试查找首个匹配的 catch 代码块。如果没有用 set_exception_handler() 设置异常处理函数, PHP 会在异常未被捕获时产生 Fatal 级错误,提示 "Uncaught Exception ..." 消息。

从 PHP 7.1.0 起 catch 可以用竖线符(|) 指定多个异常。如果在不同的类层次结构中,不同的异常需要用同样的方式处理,就特别适用这种方式。

语法

php 复制代码
try {
  可能抛出异常的代码
} catch(Exception $e) {
  当捕获到异常时运行的代码
}

示例 捕获并处理异常

php 复制代码
function divide($dividend, $divisor) {
    if($divisor == 0) {
        // throw 语句允许用户定义的函数或方法抛出异常
        throw new Exception("除数不能为0");
    }
    return $dividend / $divisor;
}

try {
    echo divide(1, 0);
} catch (Exception $e) {
    echo "出现错误,无法执行";
}
// 程序执行,输出 "出现错误,无法执行"

catch 块指示应该捕获哪种类型的异常以及用于访问异常的变量名称。在上面的示例中,异常的类型是 Exception,变量名称是 $e。

2、try...catch...finally 语句

finally 代码块可以放在 catch 之后,或者直接代替它。无论是否抛出了异常,放在 finally 里的代码总是会执行。

值得注意的是 finally 和 return 语句之间存在相互影响。如果在 try 或 catch 里遇到 return,仍然会执行 finally 里的代码。而且,遇到 return 语句时,会先执行 finally 再返回结果。此外,如果 finally 里也包含了 return 语句,将返回 finally 里的值。

示例 添加 finally 代码块

php 复制代码
function divide($dividend, $divisor) {
    if($divisor == 0) {
        // throw 语句允许用户定义的函数或方法抛出异常
        throw new Exception("除数不能为0");
    }
    return $dividend / $divisor;
}

try {
    echo divide(1, 0);
} catch (Exception $e) {
    echo "出现错误,无法执行<br>";
} finally {
    echo "总会执行";
}
// 程序执行,输出:
/*
出现错误,无法执行
总会执行
*/

3、全局异常处理程序

当允许异常冒泡到全局作用域时,它可以被全局异常处理器捕获到。 set_exception_handler() 可以设置一个函数,在没有调用其它块时代替 catch。在本质上,实现的效果等同于整个程序被 try-catch 包裹起来。

php 复制代码
set_exception_handler(?callable $callback): ?callable

设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。在 callback 调用后异常会中止。

参数

callback:当一个未捕获的异常发生时所调用的函数。该处理函数需要接受一个参数,该参数是抛出的 Throwable 对象。也可以传递 null 值用于重置异常处理函数为默认值。

返回值

返回之前定义的异常处理程序,或者在错误时返回 null。如果之前没有定义错误处理程序,也会返回 null。

示例

php 复制代码
function exception_handler(Throwable $e) {
    $code = $e->getCode();
    $message = $e->getMessage();
    $file = $e->getFile();
    $line = $e->getLine();
    echo "在文件 $file 的第 $line 行抛出了异常:[代码 $code] <br>$message";
}

set_exception_handler('exception_handler');

throw new Exception('异常');
echo "未执行";
相关推荐
4SAPI7 小时前
企业大模型API服务商推荐:从多模型接入到AI API Gateway的技术选型分析
人工智能·php
子非鱼a13 小时前
【WEB】[NewStarCTF 2023 公开赛道]include 0。0
php
DevUp14 小时前
停更老站往哪搬:PHP 老站的五条出路(番外七)
php·cms
专业程序开发源17 小时前
springboot旅游推荐系统82074-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·php·课程设计·旅游
sbjdhjd19 小时前
从“删除后重生”到认证绕过:PHP 常驻内存实验与 Cacti remote_agent 命令执行链路复盘
安全·web安全·网络安全·数据挖掘·php·网络攻击模型·安全架构
JaguarJack21 小时前
PHP 8.6 只是个小版本,三十项弃用却已在为 PHP 9.0 铺路
后端·php·服务端
BingoGo21 小时前
PHP 8.6 只是个小版本,三十项弃用却已在为 PHP 9.0 铺路
后端·php
catchadmin1 天前
Whim 是什么?一门把 PHP 被否决的设想真跑起来的实验语言
php
ID34610744201 天前
【课程设计】基于Spring Boot+Vue的游戏账号租赁系统的设计与实现-计算机毕设 附源码50345
javascript·vue.js·spring boot·python·node.js·php·课程设计
PHP实战开发录2 天前
PHP接口偶发变慢怎么查
前端·php·开发