在 PHP 后端开发中,我们经常会遇到这样的场景:需要调用多个外部 API,或者执行一些耗时的数据处理任务。传统的做法是按顺序一个接一个地执行这些操作。比如,你需要先调用 A 服务获取数据,等待其响应后,再用 A 的数据去调用 B 服务,最后处理 B 的结果。这个过程是完全同步的,意味着在 A 服务响应之前,你的 PHP 脚本会一直“卡”在那里等待,什么也做不了。如果 A 服务响应慢,或者需要调用的服务数量很多,整个请求的响应时间就会变得非常长,用户只能眼睁睁地看着页面转圈圈,最终可能因为超时而放弃。
这种“串行”执行的模式,不仅浪费了宝贵的服务器资源(因为 cpu 在等待 i/o),也严重影响了用户体验。我们渴望一种机制,能让 php 脚本在等待一个耗时操作完成的同时,去处理其他任务,或者同时发起多个独立的耗时操作,待它们全部完成后再统一处理结果。这正是异步编程的魅力所在,而
guzzlehttp/promises
Composer在线学习地址:学习地址
guzzlehttp/promises
安装 Guzzle Promises
首先,使用 Composer 轻而易举地将
guzzlehttp/promises
立即学习“PHP免费学习笔记(深入)”;
<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();
// 注册成功和失败的回调函数
$promise->then(
// 成功回调:当 Promise 被“解决”(fulfilled)时执行
function ($value) {
echo "操作成功,得到结果: " . $value . "\n";
},
// 失败回调:当 Promise 被“拒绝”(rejected)时执行
function ($reason) {
echo "操作失败,原因: " . $reason . "\n";
}
);
echo "我先去干点别的事...\n";
// 模拟异步操作完成,并“解决”Promise
// 这将在某个未来的时间点发生,例如在一个异步请求的回调中
$promise->resolve('这是异步操作的结果!');
// 模拟异步操作失败,并“拒绝”Promise
// $promise->reject('出错了,无法完成操作!');
echo "异步操作的结果已经处理了,继续。\n";运行上述代码,你会发现输出顺序是:
<pre class="brush:php;toolbar:false;">我先去干点别的事... 操作成功,得到结果: 这是异步操作的结果! 异步操作的结果已经处理了,继续。
这正是异步的魅力!
echo "我先去干点别的事..."
guzzlehttp/promises
then
<pre class="brush:php;toolbar:false;"><?php
require 'vendor/autoload.php';
use GuzzleHttp\Promise\Promise;
// 模拟第一个异步操作:获取用户ID
function fetchUserIdAsync(): Promise
{
$promise = new Promise();
// 假设2秒后获取到用户ID
// 在实际应用中,这里可能是发起一个 HTTP 请求
echo "正在获取用户ID...\n";
\GuzzleHttp\Promise\Utils::queue()->add(function () use ($promise) {
sleep(2); // 模拟耗时
$promise->resolve(123); // 假设用户ID是123
});
return $promise;
}
// 模拟第二个异步操作:根据用户ID获取用户详情
function fetchUserDetailsAsync(int $userId): Promise
{
$promise = new Promise();
echo "正在获取用户 {$userId} 的详情...\n";
\GuzzleHttp\Promise\Utils::queue()->add(function () use ($promise, $userId) {
sleep(1); // 模拟耗时
if ($userId === 123) {
$promise->resolve(['name' => '张三', 'email' => 'zhangsan@example.com']);
} else {
$promise->reject('用户不存在');
}
});
return $promise;
}
// 链式调用:先获取用户ID,再获取用户详情
fetchUserIdAsync()
->then(function ($userId) {
echo "成功获取用户ID: {$userId}\n";
return fetchUserDetailsAsync($userId); // 返回一个新的 Promise,继续链式调用
})
->then(function ($userDetails) {
echo "成功获取用户详情: " . json_encode($userDetails, JSON_UNESCAPED_UNICODE) . "\n";
})
->otherwise(function ($reason) { // 统一处理链中任何环节的错误
echo "操作链中出现错误: " . $reason . "\n";
});
echo "主程序继续执行,不等待异步操作...\n";
// 在 PHP 中,如果你的应用没有事件循环,你需要手动运行 Promise 队列来确保回调被触发
// GuzzleHttp\Promise\Utils::queue() 是全局任务队列,在实际应用中通常与事件循环集成
\GuzzleHttp\Promise\Utils::queue()->run();
echo "所有异步操作(如果已完成)都已处理完毕。\n";通过链式调用,代码逻辑变得异常清晰:先做什么,然后做什么,最后怎么处理。任何一步出错,都会直接跳到
otherwise
then
wait
$promise->wait()
$promise = new Promise(function () use (&$promise) { $promise->resolve('foo'); }); echo $promise->wait(); // 输出 "foo"登录后复制
cancel
<pre class="brush:php;toolbar:false;">$promise = new Promise(
function () use (&$promise) { /* ... */ },
function () {
// 可以在这里执行取消操作,例如关闭连接
echo "Promise 已被取消!\n";
}
);
$promise->cancel();guzzlehttp/promises
then
guzzlehttp/promises
在实际项目中,
guzzlehttp/promises
拥抱
guzzlehttp/promises
以上就是PHP异步编程痛点如何解决?GuzzlePromises助你构建高性能应用!的详细内容,更多请关注php中文网其它相关文章!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号