【PHP8.4】`$http_response_header`を取得する関数が実装される

```php
$dummy = file_get_contents('http://example.com');

var_dump($http_response_header); // ←なにこれ？
```

PHPには、[予め定義されている変数](https://www.php.net/manual/ja/language.variables.predefined.php)がいくつかあります。
有名どころとしては`$_REQUEST`・`$_SESSION`等の[スーパーグローバル変数](https://www.php.net/manual/ja/language.variables.superglobals.php)、PHPをコマンドライン実行した際に入ってくる[$argc・$argv](https://www.php.net/manual/ja/reserved.variables.argc.php)です。

そしてそれ以外にひとつだけ特殊な変数があり、[HTTPラッパー](https://www.php.net/manual/ja/wrappers.http.php)を使うと唐突に[$http_response_header](https://www.php.net/manual/ja/reserved.variables.httpresponseheader.php)という変数が生えます。

非常にわかりにくいというか理解に苦しむ仕様なので、これを関数経由で取得するRFCが提出されました。
既に受理されており、PHP8.4から使用可能になります。

以下は該当のRFC、[Add http_(get|clear)_last_response_headers() function](https://wiki.php.net/rfc/http-last-response-headers)の紹介です。


# PHP RFC: Add http_(get|clear)_last_response_headers() function

## Introduction

PHPのストリーム層を通じてHTTPリクエストを実行したとき、すなわち[HTTPラッパー](https://www.php.net/manual/en/wrappers.http.php)を使用したときに、変数[$http_response_header](https://www.php.net/manual/en/reserved.variables.httpresponseheader.php)がどこからともなく湧いて出てきます。
よくある例としては[file_get_contents()](https://www.php.net/file_get_contents)を使ったときです。

`$http_response_header`には、HTTPラッパー経由で実行したリクエストのHTTPヘッダが含まれます。
ローカルスコープに変数を生成するという動作は追加情報を得るための最もひどい方法のひとつであるため、[$php_errormsg](https://www.php.net/manual/en/reserved.variables.phperrormsg.php)など類似の機能は削除されつつあります。
この変数も[PHP8.1で非推奨にしたい](https://wiki.php.net/rfc/deprecations_php_8_1#predefined_variable_http_response_header)という話はありましたが、当時は適切な代替手段がなかったため提案の対象外になりました。

ここでは、`$php_errormsg`を置き替えた`error_get_last()/error_clear_last()`と同様に、`$http_response_header`を置き替える関数を提案します。


## Motivation

関数を導入する主な目的は、変数`$http_response_header`をいずれ削除するためです。

この変数を作成するためにエンジン関数`zend_set_local_var_str()`が使われています。
`$http_response_header`は、この関数とその兄弟`zend_set_local_var()`を今なお使用している唯一の変数です。

さらにこの変数はopcacheやJIT環境では個別に特殊な処理が必要であるため、opcache下では挙動が変わってしまう可能性があります。

この機能の削除による影響については、Backward Incompatible Changesを参照してください。


## Proposal

2つの関数`http_get_last_response_header(): ?array`・`http_clear_last_response_header(): void`を追加します。

`http_get_last_response_header()`は、`$http_response_header`と同じHTTPヘッダの内容を返します。
`http_clear_last_response_header()`は、HTTPヘッダをクリアします。


## Backward Incompatible Changes

このRFCではまだ`$http_response_header`を非推奨にしないため、下位互換性のない変更点はありません。

この機能の使用状況を[Exakat](https://www.exakat.io/)で分析しました。
Composerパッケージ、OSSプロジェクト等900件以上を分析したところ、30のプロジェクトで65か所が見つかりました。
使用のほとんどはGuzzleやOauth等のライブラリに由来するものでした。

`$http_response_header`が削除された場合のpolyfillは不可能ですが、以下のようにすることで同じコードを使い続けることができます。

```php
$content = file_get_contents('http://example.com/');
if (function_exists('http_get_last_response_headers')) {
    $http_response_header = http_get_last_response_headers();
}
```

この機能の使用頻度が少ないこと、互換のある記述が可能であること、エンジンやオプティマイザ開発の効率化を考えると、非推奨の段階を経ずに削除することも合理的かもしれません。


## Version

PHP8.4。

## Vote

投票期間は2024/01/29～2024/02/14、投票の2/3の賛成で受理されます。

本RFCは賛成15反対1の賛成多数で可決されました。


## References

[影響の出るライブラリ一覧](https://gist.github.com/exakat/454e503458e231dc0695837ad2561540)。


# 感想


この手の勝手に生える変数、昔はもっと存在していたのですが、[register_globals](https://qiita.com/gongo/items/91b8728701cbbb41584e)はPHP4.2で非推奨になり、[$HTTP_RAW_POST_DATA](https://www.php.net/manual/ja/migration56.deprecated.php)はPHP5.6で非推奨になり、[$php_errormsg](https://www.php.net/manual/ja/reserved.variables.phperrormsg.php)もPHP7.2で非推奨になり、とどんどん片付けられつつあり、現在も残っているのはこの[$http_response_header](https://www.php.net/manual/ja/reserved.variables.httpresponseheader.php)と、コマンドライン実行時に入ってくる[$argc・$argv](https://www.php.net/manual/ja/reserved.variables.argc.php)だけです。
そして`$http_response_header`もRFCのとおり、PHP9あたりで非推奨にされることは既定路線でしょう。

ということで最後まで残るのは`$argc・$argv`です。
これらについては今のところどうこうする話は出ていないようですが、いずれは他と合わせてスーパーグローバル変数`$_ARGC・$_ARGV`になるか、`get_argc()`のような関数になるかもしれませんね。

あともうひとつ気になることとしては、どうして`$GLOBALS`だけ_がついてないんだ。