编程

PHP 8.4: 新增 http_(get|clear)_last_response_headers 函数

502 2024-04-19 03:03:00

PHP 提供了一个 HTTP 包装器,可以使用标准文件系统函数访问远程 HTTP 内容。例如,file_get_contents() 函数可以获取远程 HTTP 资源以及文件系统上的常规文件。

在成功建立远程连接后,HTTP 包装器填充一个名为 $http_response_header 的本地变量。此变量是在局部作用域中填充的,它不是超全局变量。

这是一个历史组件,曾经用于使 HTTP 头可用,但这个变量的“魔力”性质可能会令人困惑,需要在 IDE 和静态分析器中进行特殊处理。

file_get_contents('https://php.watch');
var_dump($http_response_header);
array(15) {
  [0]=> string(15) "HTTP/1.1 200 OK"
  [1]=> string(30) "Alt-Svc: h3=":443"; ma=2592000"
  [2]=> string(44) "Cache-Control: max-age=1800,public,immutable"
  // ...
}

PHP 8.4 添加了两个新函数 http_get_last_response_headershttp_clear_last_response_headers,这两个函数可用于获取和清除最后一个 HTTP 包装器响应的 HTTP 头,这两个函数可替换 $http_response_header 变量。

$http_response_header 变量未被弃用
截至 PHP 8.4 ,$http_response_header 变量未被弃用。不过,推荐 PHP 8.4 以上版本的应用中使用新函数。

新增 http_(get|clear)_last_response_headers 函数

这两个新函数,http_get_last_response_headershttp_clear_last_response_headers 提供了与 http_response_header 变量相似的功能,但清晰度有所提高。

例如,IDE和静态分析器可以使用 http_get_last_response_headershttp_clear_last_response_headers 函数模板来了解变量的参数和返回类型,而不用先去了解 $http_response_header 变量。

$http_response_header 不会被这些函数修改
http_(get|clear)_last_response_headers 没有触碰 $http_response_header 变量。清除 $http_response_header 变量不会影响 http_get_last_response_headers() 函数(它将继续返回值),而调用 http_clear_last_response_headers() 不会清除 $http_response_header 变量。

http_get_last_response_headershttp_clear_last_response_headers 函数的作用域不限于本地调用上下文。调用 http_get_last_response_headers() 可以返回最后一个 HTTP 包装响应头,即使它没有在作用域内调用。为了防止意外使用来自另一个请求的 HTTP 响应,请确保调用 http_clear_last_response_headers()

http_get_last_response_headers

/**  
 * Returns HTTP response headers from the last HTTP request that
 * used the HTTP wrapper. If the request failed, or if there is no
 * last HTTP request, it returns null.
 *
 * @return array|null  
 **/
function http_get_last_response_headers(): ?array {}

在成功响应的 HTTP 包装器调用之后, http_get_last_response_headers 函数返回一个 HTTP 响应头数组。如果没有 HTTP 响应,或者请求失败(例如,由于DNS 解析失败),则返回值将为 null。

$http_response_header 不同,此函数返回的值不在作用域内。即使最后一个 HTTP 请求是在另一个函数调用作用域内发出的,它也可以返回最后一次 HTTP 包装调用的 HTTP 头。

请注意,包括 404403 等在内的所有 HTTP 响应也被视为有效的 HTTP 响应,此函数还返回它们的响应头。

http_get_last_response_headers(); // null

file_get_contents('https://php.watch/versions/8.4/http_get-clear_last_response_headers');

http_get_last_response_headers(); // ['HTTP/1.1 200 OK', 'Cache-type: text/html', ...]

即使 $http_response_header 变量被修改,http_get_last_response_headers() 也返回响应头(如果可用).

在第一次使用 http 包装器之前,$http_response_header 变量不会被定义。在这种情况下,http_get_last_response_headers() 函数返回 null,并且不发出错误/警告/通知。

http_clear_last_response_headers

/**  
 * Clears the HTTP headers from the last HTTP wrapper HTTP response.
 **/
function http_clear_last_response_headers(): void {}

调用 http_clear_last_response_headers 将清理内部存储的HTTP标头,后续的 http_get_last_response_headers 将返回 null

调用该函数对 $http_response_header 变量没有影响。不过,由于 http_get_last_response_headers 返回值没有作用域,http_clear_last_response_headers()也将全局清理该返回值。

替换 $http_response_header 变量

$http_response_header 变量是一种历史行为,它是在当前作用域内神奇地隐式创建的变量。请考虑将变量替换为 http_(get|clear)_last_response_headers 函数调用,因为它提供了更可预测和直观的代码流。

PHP 8.4 没有弃用 $http_response_header 变量。但是,建议尽可能使用新函数。

跨版本兼容:

  file_get_contents('https://php.watch/versions/8.4/http_get-clear_last_response_headers');

- $headers = $http_response_header;
+ if (\PHP_VERSION_ID >= 80400) {
+   $headers = http_get_last_response_headers();
+   http_clear_last_response_headers();
+ }
+ else {
+   $headers = $http_response_header;
+ }

PHP >=8.4 only

  file_get_contents('https://php.watch/versions/8.4/http_get-clear_last_response_headers');

- $headers = $http_response_header;
+ $headers = http_get_last_response_headers();
+ http_clear_last_response_headers();

向后兼容性影响

不可能在旧版 PHP 中 polyfill 该函数,因为 $http_response_header 只在本地作用域可用,而 http_(get|clear)_last_response_headers 并不返回/清理作用域变量。