【PHP7.4】レガシーな仕様はどんどんしまっちゃおうねぇ

恒例の仕様凍結直前[駆け込みRFC](https://qiita.com/rana_kualu/items/6ac293f238c4e6000720)第二弾。
色々な古い書き方について、PHP7.4でE_DEPRECATEにし、PHP8で削除を目指すRFCが投票中です。

以下は[Deprecations for PHP 7.4](https://wiki.php.net/rfc/deprecations_php_7_4)の日本語訳です。


# Deprecations for PHP 7.4

## Introduction

このRFCでは、以下に列挙されている機能についてPHP7.4で非推奨とし、PHP8で削除することを提案します。


## Proposal

各提案は個別に投票を行い、投票数の2/3+1の賛成で受理されます。
投票開始は2019/07/08、投票終了は2019/07/22です。

### The 'real' type

現在のPHPでは、float型にはdoubleとrealという2種類のエイリアスが存在します。
後者は滅多に使用されず、廃止されるべきです。
これは`(real)`キャストと、[is_real](https://www.php.net/manual/ja/function.is-real.php)関数の両方が含まれます。
[settype](https://www.php.net/manual/ja/function.settype.php)関数は`real`をサポートしていないため影響はありません。

プログラム側の対応は簡単で、全ての`(real)`キャストを`(float)`に、`is_real`関数を`is_float`に置き換えるだけです。

Proposal：`(real)`キャストおよび`is_real`関数をE_DEPRECATEDにします

2019/07/11時点では賛成24反対6で、おそらく受理されます。


### Magic quotes legacy

悪名高いmagic_quotesはPHP5.4で削除され、magic_quotesの値を調べる関数はそれ以来ずっとfalseを返しています。
PHP7にはmagic_quotesに関する機能は全く存在しないため、これらの関数はもはや存在する意義がありません。

Proposal：[get_magic_quotes_gpc](https://www.php.net/manual/ja/function.get-magic-quotes-gpc.php)関数および[get_magic_quotes_runtime](https://www.php.net/manual/ja/function.get-magic-quotes-runtime.php)関数をE_DEPRECATEDにします。
この変更が影響するのは、もはやサポートされていないPHP5.4以前のレガシーなコードだけです。

2019/07/11時点では賛成34反対0で、おそらく受理されます。


### array_key_exists() with objects

[array_key_exists](https://www.php.net/manual/ja/function.array-key-exists.php)は互換性のためにオブジェクトにも対応しています。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/68a22923-d807-5a95-548b-06cf06718a44.png)

オブジェクトに対するarray_key_existsは問題があります。
プロパティの可視性を無視して直接中身を覗きます。
また、配列のキーとオブジェクトのキーの取り扱いの違いが考慮されていないため、数値キーのプロパティに対して正しくない結果を返す可能性があります。

さらにarray_key_existsがオブジェクトを受け入れるという事実は、ArrayAccessオブジェクトをarray_key_existsで適切に操作できるのだとユーザに誤解させかねません。
これは誤りで、array_key_existsは実際にはArrayAccessをサポートしていません。

Proposal：array_key_existsにオブジェクト渡すとE_DEPRECATEDにします。

2019/07/11時点では賛成32反対0で、おそらく受理されます。


### FILTER_SANITIZE_MAGIC_QUOTES

magic_quotesはPHP5.3で廃止され、PHP5.4で削除されました。

[Filter関数](https://www.php.net/manual/ja/book.filter.php)は、magic_quotesと同じ動作を[addslashes](https://www.php.net/manual/ja/function.addslashes.php)を呼び出すことで再現するサニタイズフィルタを提供しています。
PHP7.3では、magic_quotesという単語から抜け出すため、FILTER_SANITIZE_MAGIC_QUOTESのエイリアスとして[FILTER_SANITIZE_ADD_SLASHESを追加](https://qiita.com/rana_kualu/items/48e6e4baaeb265ab9fa7#added-the-add_slashes-sanitization-mode)しました。

Proposal：FILTER_SANITIZE_MAGIC_QUOTESをE_DEPRECATEDにします。かわりにFILTER_SANITIZE_ADD_SLASHESを使ってください。

2019/07/11時点では賛成33反対0で、おそらく受理されます。


### Reflection export() methods

全てのリフレクションクラスは[Reflectorインターフェイス](https://php.net/manual/ja/class.reflector.php)を実装しており、`__toString()`と`export()`という2つのメソッドが存在します。
[後者](https://www.php.net/manual/ja/reflector.export.php)は静的メソッドであり、一見して引数を受け付けません。

しかし実際は、各サブクラスにおいて引数を受け入れるように[オーバーライド](https://www.php.net/manual/ja/reflectionclass.export.php)されています。
これは本来は互換性のない引数のエラーが発生するはずですが、内部的にエラーを抑制して実装されています。

exportメソッドは、本質的にコンストラクタ+`__toString`と同じです。

```php
	// 同じ
	ReflectionFunction::export('foo');
	echo new ReflectionFunction('foo'), "\n";

	// 同じ
	$str = ReflectionFunction::export('foo', true);
	$str = (string) new ReflectionFunction('foo');
```

exportメソッドはPHPの継承の規則に反していて混乱を招くため、全く不要です。

Proposal：Reflectorインターフェイスと全ての実装クラスから`exports`メソッドをE_DEPRECATEDにします。PHP8で実装を削除します。

2019/07/11時点では賛成25反対3で、おそらく受理されます。


### mb_strrpos() with encoding as 3rd argument

[mb_strrpos](https://www.php.net/manual/ja/function.mb-strrpos.php)のドキュメントにはこのようなことが書かれています。

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/356d46f0-62e8-6aad-0865-8c4af7ecf939.png)

非推奨と書かれてはいますが、現状特に警告が出たりはしません。
両方の引数を受け入れるため、このパラメータは他のパラメータとは異なる動作をします。
たとえばstrict typesにしても型エラーが出ません。
PHP5.1とPHP7.4の両方をサポートするアプリはほぼ存在しないと思われるので、ここの動作を変更しても、後方互換性に関する重大な問題は発生しません。

Proposal：mb_strrpos関数の第三引数に文字列を渡すとE_DEPRECATEDにします。PHP8で実装を削除します。

2019/07/11時点では賛成32反対0で、おそらく受理されます。


### implode() parameter order mix

歴史的な経緯により、[implode](https://www.php.net/manual/ja/function.implode.php)関数は引数`$glue`と`$pieces`を、どちらの順番でも受け入れることができます。
[join](https://www.php.net/manual/ja/function.join.php)関数も同じです。

Proposal：`implode(array, string)`の順番での引数をE_DEPRECATEDにします。`implode(array)`は引き続き許可されます。

2019/07/11時点では賛成27反対5で、おそらく受理されます。


### Unbinding $this from non-static closures

現在、`$closure->bindTo(null)`を用いてクロージャから`$this`を削除することができます。
PHP8では非静的メソッドの静的呼び出しが削除されたため、非静的メソッドには常に`$this`が存在することが保証されました。
非静的メソッド内で宣言された非静的クロージャに対して、`$this`が常に存在するという同様の保証を得たいと思います。
さもなくば、通常のアクセスもしくはクロージャからのアクセスの何れかに対して、不合理が発生するでしょう。

Proposal：クロージャから`$this`の削除をE_DEPRECATEDにします。特に非静的メソッド内で宣言された非静的クロージャに対して適用されます。`$this`が不要な場合は[静的クロージャ](https://www.php.net/manual/ja/functions.anonymous.php#functions.anonymous-functions.static)を使うことで余計なバインドを避けられます。

2019/07/11時点では賛成31反対0で、おそらく受理されます。


### hebrevc() function

[hebrevc](https://www.php.net/manual/ja/function.hebrevc.php)関数は、[hebrev](https://www.php.net/manual/ja/function.hebrev.php)関数の結果を[nl2br](https://www.php.net/manual/ja/function.nl2br.php)するのと同じです。
これはヘブライ語のテキストを論理順から視覚順に変換する関数です。

視覚的順序付けの使用は、[Unicode bidi](https://developer.mozilla.org/ja/docs/Web/CSS/unicode-bidi)に対応していない端末など、ごく一部のコンテキストにのみ使用するべきです。
[W3C](https://www.w3.org/International/questions/qa-visual-vs-logical)が表明しているように、視覚的順序付けはHTMLには使用しないでください。
hebrevc関数はこの原則に明らかに反しています。

Proposal：hebrevc関数をE_DEPRECATEDにします。

2019/07/11時点では賛成20反対8で、受理されるか微妙なところです。


### convert_cyr_string()

[convert_cyr_string](https://www.php.net/manual/ja/function.convert-cyr-string.php)関数は、キリル文字のテキストを他のキリル文字セットに変換します。
変換する文字コードは、`convert_cyr_string($str, "k", "i")`のように理解しがたい1文字で指定しなければなりません。
この関数は、PHPに文字コード変換のための一般的手法が存在していなかった頃の古い関数です。
現在は[mb_convert_encoding](https://www.php.net/manual/ja/function.mb-convert-encoding.php)、[iconv](https://www.php.net/manual/ja/function.iconv.php)、あるいは[UConverter](https://www.php.net/manual/ja/class.uconverter.php)などが、この目的のために使用されます。

Proposal：convert_cyr_string関数をE_DEPRECATEDにします。

2019/07/11時点では賛成17反対7で、受理されるか微妙なところです。


### money_format()

[money_format](https://www.php.net/manual/ja/function.money-format.php)関数は、ロケールを見て金額をフォーマットします。
これはC言語の[strfmon](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/strfmon.3.html)を使用していますが、これは全てのプラットフォームがサポートしているわけではなく、特にWindowsでは利用できません。
今日では[intl](https://www.php.net/manual/ja/book.intl.php)が提供する[NumberFormatter::formatCurrency](https://www.php.net/manual/ja/numberformatter.formatcurrency.php)を使用すべきです。
これはプラットフォームに依存せず、ロケールにも依存しません。
intlではさらに金額フォーマットをパースする[NumberFormatter::parseCurrency](https://www.php.net/manual/ja/numberformatter.parsecurrency.php)も提供しています。

あと、MacOSでのstrfmonの実装を見ていると、どうもこの関数はバッファオーバーランしているように見受けられます。
これはすなわち、この関数が十分なテストを受けていないことを示しています。

Proposal：money_format関数をE_DEPRECATEDにします。

2019/07/11時点では賛成22反対8で、おそらく受理されます。


### ezmlm_hash()

[ezmlm_hash](https://www.php.net/manual/ja/function.ezmlm-hash.php)関数は、EZMLM/QMailメーリングリストが理解できるメールアドレスのハッシュを作成します。
EZMLM/QMailは最終リリースが2007年であり、全くメンテナンスされていないため、この関数を必要とするPHP開発者は限りなく少数です。
この関数は、元々php.netのメーリングリストで使用するために実装されたものです。
必要であればユーザランドで簡単に実装が可能です。

Proposal：ezmlm_hash関数をE_DEPRECATEDにします。

2019/07/11時点では賛成25反対4で、おそらく受理されます。


### restore_include_path() function

[restore_include_path](https://www.php.net/manual/ja/function.restore-include-path.php)関数は、本質的に`ini_restore('include_path')`のエイリアスです。
[restore_error_handler](https://www.php.net/manual/ja/function.restore-error-handler.php)や[restore_exception_handler](https://www.php.net/manual/ja/function.restore-exception-handler.php)と異なり、この関数はスタック上で動作せず、必ず初期値にリセットされます。

set_error_handler()とrestore_error_handler()をペアで使用して一時的に動作を変更する操作は有用ですが、set_include_path()とrestore_include_path()を同様にペアで使用することは安全ではありません。
従って、この関数は`ini_restore('include_path')`と別に存在する利点はなく、誤った使い方を助長するだけです。

Proposal：restore_include_path関数をE_DEPRECATEDにします。

2019/07/11時点では賛成19反対9で、受理されるか微妙なところです。


### allow_url_include

[allow_url_include](https://www.php.net/manual/ja/filesystem.configuration.php#ini.allow-url-include)ディレクティブは、[require](https://www.php.net/manual/ja/function.require.php)、[require_once](https://www.php.net/manual/ja/function.require-once.php)、[include](https://www.php.net/manual/ja/function.include.php)、[include_once](https://www.php.net/manual/ja/function.include-once.php)の各言語構造にURLストリームラッパーの使用を許可します。
このディレクティブはデフォルト無効で、使用するには[allow_url_fopen](https://www.php.net/manual/ja/filesystem.configuration.php#ini.allow-url-fopen)も有効にする必要があります。

includeするパスに外部入力を使用している場合、このオプションを有効にするとセキュリティ上の問題が発生します。
外部ドメインからPHPファイルをインクルードする仕様そのものがそもそも極めて問題であり、大きなセキュリティリスクが存在するため、廃止されるべきです。

Proposal：allow_url_includeディレクティブが有効である場合E_DEPRECATEDが発生します。

2019/07/11時点では賛成30反対0で、おそらく受理されます。


## Backward Incompatible Changes

PHP7.4では、非推奨の警告が表示されます。
PHP8では、動作しなくなります。


## Changelog

元々は以下の項目も廃止予定に含まれていましたが、最終的に対象外になりました。

・[get_called_class](https://php.net/manual/ja/function.get-called-class.php)。あまり考えられていなかった。
・[enable_dl](https://www.php.net/manual/ja/info.configuration.php#ini.enable-dl)。当初の提案が間違っていた。
・INPUT_SESSIONとINPUT_REQUEST。そもそも実装されてなかったので[直接削除した](https://qiita.com/sj-i/items/5dae03d6ad66b9f5f3da#nikic-remove-input_session-and-input_request)。
・[is_writeable](https://www.php.net/manual/ja/function.is-writeable.php)。ただの誤字だけど検索しやすいから好ましいとか主張した人がいたので取り下げられた。
・[apache_request_headers](https://www.php.net/manual/ja/function.apache-request-headers.php)。大きな問題の中のひとつなので、この関数だけ消して終わりではなく大規模な考察が必要。
・[hebrev](https://www.php.net/manual/ja/function.hebrev.php)。一部の環境ではまだ有用なため。ただしhebrevcは削除する。
・`enable_argc_argv`、と書いてあるんだけど全く出てこないんだけど存在するのこれ？


# 感想

ほとんどは削除されて当然というか、そもそも全く知らない関数だった。
hebrevcとかconvert_cyr_stringとか聞いたこともないよ。
使ってる人いるんですかね？
あとmagic_quotesは、むしろどうしてPHP7.0で削除されなかったんだと聞きたいくらいですね。
概ね順当に削除されそうでなによりです。

でも`Reflection::export()`は個人的にデバッグとかで時々使っているからちょっと困るかな。
`__toString()`はなんというか、これを使うのだ、と明示できないからちょっと気持ち悪いというかなんというか。