PHP使用Guzzle发起的异步请求示例详解
发布时间:2026/9/27 23:06:19来源:尧图网络
Guzzle中的异步请求使用Guzzle发起异步请求Guzzle是一个PHP的HTTP客户端它在发起http请求时不仅可以同步发起还可以异步发起。12345678$clientnewClient();$requestnewRequest(GET,http://www.baidu.com);$promise$client-sendAsync($request)-then(function($response) {echo$response-getBody();});// todo somethingecho1;$promise-wait();PHP发起HTTP请求的几种方式curl使用libcurl库允许你与各种的服务器使用各种类型的协议进行连接和通讯。stream通过流的方式获取和发送远程文件该功能需要ini配置allow_url_fopenon。关于php的流更多参考PHP流Stream的概述与使用详解在guzzle中可以兼容使用这两种的任意一种或者是用户自定义的http handler1234567891011121314151617181920functionchoose_handler(){$handler null;if(function_exists(curl_multi_exec) function_exists(curl_exec)) {$handler Proxy::wrapSync(newCurlMultiHandler(),newCurlHandler());}elseif(function_exists(curl_exec)) {$handlernewCurlHandler();}elseif(function_exists(curl_multi_exec)) {$handlernewCurlMultiHandler();}if(ini_get(allow_url_fopen)) {$handler$handler? Proxy::wrapStreaming($handler,newStreamHandler()):newStreamHandler();}elseif(!$handler) {thrownew\RuntimeException(GuzzleHttp requires cURL, the .allow_url_fopen ini setting, or a custom HTTP handler.);}return$handler;}可以看出guzzle会优先使用curl然后选择使用streamProxy::wrapStreaming($handler, new StreamHandler())是一个流包装器。12345678910publicstaticfunction wrapStreaming(callable $default,callable $streaming) {returnfunction (RequestInterface $request, array $options) use ($default, $streaming) {returnempty($options[stream])? $default($request, $options): $streaming($request, $options);};}什么是URIURI的组成URIUniform Resource Identifier统一资源标识符。scheme:[//[user:password]host[:port]][/]path[?query][#fragment]请求的组装Guzzle发起请求大致分为两个阶段第一阶段负责将需要请求的uri组装成各种内部定义的类。Client类这是一个发起客户端的调用者后续所有的调用需要基于这个负责的类实现它负责提供一个 handler ,这是一个客户端发起http请求的句柄其中Guzzle实现curl和stream调用的无感知就是在这里实现的同时开发者也可以自定义请求协议。123456789101112131415161718192021// 根据系统当前状态选择一个发起Http请求的协议的方法句柄functionchoose_handler(){$handler null;if(function_exists(curl_multi_exec) function_exists(curl_exec)) {$handler Proxy::wrapSync(newCurlMultiHandler(),newCurlHandler());}elseif(function_exists(curl_exec)) {$handlernewCurlHandler();}elseif(function_exists(curl_multi_exec)) {$handlernewCurlMultiHandler();}if(ini_get(allow_url_fopen)) {$handler$handler? Proxy::wrapStreaming($handler,newStreamHandler()):newStreamHandler();}elseif(!$handler) {thrownew\RuntimeException(GuzzleHttp requires cURL, the .allow_url_fopen ini setting, or a custom HTTP handler.);}return$handler;}Request类负责定义一个uriPromise类这个类负责承载类请求发起前的各种准备工作完成后的结果还包括两个回调请求成功回调、请求失败回调,同时请求发起中的队列延迟等处理也是在这个类里。其中组装阶段最重要的方法是私有方法private function transfer(RequestInterface $request, array $options)它负责将用户通过各种方法传入的uri和client类的各种属性组合然后使用这些属性生成一个新的类 Promise 类。请求的发起Client的各种属性组装完成后就可以使用得到的Promise类发起http请求了这里主要是通过一个 wait() 方法。同步调用与异步调用在同步方法内部的调用同步方法是在内部组装好一个Promise之后立刻发起wait()调用。12345publicfunction send(RequestInterface $request, array $options []){$options[RequestOptions::SYNCHRONOUS] true;return$this-gt;sendAsync($request, $options)-gt;wait();}wait的实现wait() 方法的实现逻辑也很简单递归调用wait()方法直到result属性不是PromiseInterface实现类或者state不是pending然后将结果逐层输出。这里说一下这个state的pending状态这是一个PromiseInterface实现类的初始化状态表示改实现类还没有完成需要继续wait。1234567891011121314151617publicfunction wait($unwrap true){$this-gt;waitIfPending();$inner $this-gt;result instanceof PromiseInterface? $this-gt;result-gt;wait($unwrap): $this-gt;result;if($unwrap) {if($this-gt;result instanceof PromiseInterface|| $this-gt;state self::FULFILLED) {return$inner;}else{// Its rejected so unwrap and throw an exception.throwexception_for($inner);}}}waitIfPending() 如果promise类还处于pending状态就执行。主要是执行改实现类的waitFn方法。最外层promise执行完成后执行queue()-run() 这个方法内部循环执行队列内方法直到队列为空。至此Guzzle就能将组装进来的多个request和各种方法执行完毕。123456789101112131415161718192021222324252627privatefunctionwaitIfPending(){if($this-state ! self::PENDING) {return;}elseif($this-waitFn) {$this-invokeWaitFn();}elseif($this-waitList) {$this-invokeWaitList();}else{// If theres not wait function, then reject the promise.$this-reject(Cannot wait on a promise that has .no internal wait function. You must provide a wait .function when constructing the promise to be able to .wait on a promise.);}queue()-run();if($this-state self::PENDING) {$this-reject(Invoking the wait callback did not resolve the promise);}}publicfunctionrun(){/** var callable $task */while($taskarray_shift($this-queue)) {$task();}}waitFn是什么回到前面提到的transfer()函数。123$handler$options[handler];// 返回一个promise类这个类有一个属性是waitFnreturnPromise\promise_for($handler($request,$options));这里我们看 $handler 是什么它是一个HandleStack类就是我们在new Client时选择的发起Http请求的协议的方法句柄实例化的类。br /之后的调用依次是 HandleStack-__invoke、RedirectMiddleware-__invoke、PrepareBodyMiddleware-__invoke。执行$fn($request, $options);方法经过前面的逐层处理此时的$fn就是HandleStack内部的Proxy包装的方法无论使用哪种协议都会在各自的实现里实例化一个拥有waitFn的Promise的实例。1234567// curl的实现$promisenewPromise([$this,execute],function()use($id) {return$this-cancel($id);});复制讲解由此可以直到waitFn方法就是各自协议的实现类的请求发起方法。then() 方法会将promise本身再封装一层promise并将原先的waitFn和then()的回调方法打包进waitFnList属性里。queue() 是的入队时机当请求执行完成后依次调用 processMessages()、promise-resolve()、settle()、FulfilledPromise-then()将请求结果插入队列。1234567891011$queue-add(staticfunction()use($p,$value,$onFulfilled) {if($p-getState() self::PENDING) {try{$p-resolve($onFulfilled($value));}catch(\Throwable$e) {$p-reject($e);}catch(\Exception$e) {$p-reject($e);}}});以上就是PHP使用Guzzle发起的异步请求示例详解的详细内容
网站建设高端定制企业官网