在 PHP 的世界里,我们习惯了代码自上而下、一步一步地同步执行。这在大多数情况下都很好用,但当你的应用需要与外部世界打交道时,比如调用远程 API、进行耗时的数据库查询,或者处理文件 I/O 时,同步执行的弊端就显现出来了:你的程序会“卡住”,直到这些外部操作完成,用户只能眼巴巴地等着。
想象一下这样的场景:你需要同时从三个不同的微服务获取数据,然后将它们组合起来显示给用户。如果采用传统的同步方式,你可能需要这样写:
<pre class="brush:php;toolbar:false;">$data1 = callServiceA(); // 等待服务A响应 $data2 = callServiceB(); // 等待服务B响应 $data3 = callServiceC(); // 等待服务C响应 // 处理并组合数据 processData($data1, $data2, $data3);
这不仅意味着用户需要等待三个服务串行执行的总时间,而且当逻辑变得更复杂,需要根据一个异步操作的结果再发起另一个异步操作时,你很快就会陷入臭名昭著的“回调地狱”(Callback Hell),代码层层嵌套,难以阅读和维护。
好在,PHP 社区为我们提供了 Composer 这个强大的包管理器,它让引入外部库变得轻而易举。而
guzzlehttp/promises
立即学习“PHP免费学习笔记(深入)”;
什么是 Promise?
简单来说,Promise 代表了一个异步操作的最终结果。这个结果可能在未来某个时间点可用,也可能永远不会可用(因为操作失败了)。Promise 有三种状态:
一个 Promise 一旦从 Pending 状态转变为 Fulfilled 或 Rejected,它的状态就不可逆转。
首先,使用 Composer 安装
guzzlehttp/promises
<pre class="brush:php;toolbar:false;">composer require guzzlehttp/promises
安装完成后,你就可以在代码中使用了。下面是一个简单的例子,展示了 Promise 的基本用法:
<pre class="brush:php;toolbar:false;"><?php
require 'vendor/autoload.php';
use GuzzleHttp\Promise\Promise;
// 创建一个 Promise 实例
$promise = new Promise();
// 使用 then() 方法注册回调函数
// 第一个参数是成功时的回调 (onFulfilled)
// 第二个参数是失败时的回调 (onRejected)
$promise->then(
function ($value) {
// 当 Promise 成功时执行
echo 'Promise 已成功,值为: ' . $value . PHP_EOL;
return "Hello, " . $value; // 返回一个新值,传递给链中的下一个 then
},
function ($reason) {
// 当 Promise 失败时执行
echo 'Promise 已失败,原因为: ' . $reason . PHP_EOL;
}
)
->then(function ($value) {
// 这个 then 会接收到上一个 then 的返回值
echo "链式调用成功,新值为: " . $value . PHP_EOL;
});
// 模拟异步操作完成,并成功解决 Promise
echo "正在解决 Promise..." . PHP_EOL;
$promise->resolve('reader.'); // 这会触发 onFulfilled 回调
echo "-------------------" . PHP_EOL;
// 另一个 Promise 示例,演示拒绝
$rejectedPromise = new Promise();
$rejectedPromise->then(
null, // 不处理成功情况
function ($reason) {
echo '被拒绝的 Promise 已失败,原因为: ' . $reason . PHP_EOL;
}
);
echo "正在拒绝 Promise..." . PHP_EOL;
$rejectedPromise->reject('Something went wrong!'); // 这会触发 onRejected 回调
// 同步等待 Promise 完成 (在实际异步场景中,通常与事件循环结合使用)
// $promise->wait();
// $rejectedPromise->wait(); // 如果不捕获异常,这里会抛出 RejectionException运行上述代码,你会看到:
<pre class="brush:php;toolbar:false;">正在解决 Promise... Promise 已成功,值为: reader. 链式调用成功,新值为: Hello, reader. ------------------- 正在拒绝 Promise... 被拒绝的 Promise 已失败,原因为: Something went wrong!
从上面的例子中,我们可以看到
guzzlehttp/promises
then()
then()
resolve($value)
reject($reason)
resolve()
reject()
then
then
then
回到我们最初的场景:同时请求三个微服务。使用 Guzzle Promises,我们可以这样实现:
<pre class="brush:php;toolbar:false;"><?php
require 'vendor/autoload.php';
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\Utils; // 提供了 all(), settle() 等辅助函数
// 模拟异步函数,返回一个 Promise
function fetchServiceData(string $serviceName, int $delay, bool $shouldFail = false): Promise
{
$promise = new Promise();
// 实际项目中,这里会是发起 cURL 请求或数据库查询等异步操作
// 简单模拟延迟和成功/失败
echo "开始请求 {$serviceName}..." . PHP_EOL;
// 在实际的异步场景中,你需要一个事件循环来驱动这些 Promise
// 这里我们只是模拟,并最终通过 resolve/reject 来完成 Promise
// 假设在 $delay 秒后完成操作
if ($shouldFail) {
// 模拟失败
$promise->reject(new \Exception("{$serviceName} 请求失败!"));
} else {
// 模拟成功
$promise->resolve("{$serviceName} 的数据");
}
return $promise;
}
// 同时发起三个模拟请求
$promise1 = fetchServiceData('服务A', 2);
$promise2 = fetchServiceData('服务B', 1, true); // 模拟服务B失败
$promise3 = fetchServiceData('服务C', 3);
// 使用 Utils::all() 等待所有 Promise 完成
// all() 会在所有 Promise 都成功时才成功,只要有一个失败,它就失败
$allPromises = Utils::all([$promise1, $promise2, $promise3]);
$allPromises->then(
function (array $results) {
echo "所有服务数据获取成功!" . PHP_EOL;
print_r($results);
},
function ($reason) {
echo "有服务请求失败!原因:" . $reason->getMessage() . PHP_EOL;
}
);
// 由于 PHP 默认是同步的,为了让 Promise 的回调被触发,
// 你需要运行任务队列或者同步等待 Promise 完成。
// 在实际的事件循环环境中 (如 ReactPHP, Amphp),这通常由事件循环自动处理。
// 这里我们使用 wait() 强制同步等待,这会阻塞程序直到 Promise 完成。
try {
$allPromises->wait();
} catch (\Exception $e) {
// wait() 会抛出异常,所以需要捕获
echo "Wait 过程中捕获到异常: " . $e->getMessage() . PHP_EOL;
}
echo "程序执行完毕。" . PHP_EOL;在这个例子中,
Utils::all()
then()
otherwise()
try-catch
GuzzleHttp\Promise\Utils
all()
some()
any()
settle()
guzzlehttp/promises
guzzlehttp/promises
GuzzleHttp\Promise\Utils::queue()->run()
guzzlehttp/promises
guzzlehttp/promises
以上就是告别回调地狱:GuzzlePromises如何优雅处理PHP异步操作的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号