却下されたPHP RFCを見てみる

[2年ぶり](https://qiita.com/rana_kualu/items/09e85bf84175a9b82e11)。
この2年くらいで却下されたRFCが10個になってたので、それぞれを見てみます。

つまり、ここに紹介されたような内容は当面PHP本体に入ることはないということです。
もっとも[Typed Properties 2.0](https://qiita.com/rana_kualu/items/9b4502d229d19635ef34)のように説得力を持たせれば[逆転もできる](https://qiita.com/rana_kualu/items/644def9847b116c8f108#typed-properties)ので、何か提案したいと考えている人は参考にしてみてはどうでしょう。


# Declined RFC

## [Making stdClass iterable](https://wiki.php.net/rfc/iterable-stdclass)

賛成7、反対25で却下。

stdClassを[Iterable](http://php.net/manual/ja/language.types.iterable.php)にしよう、という提案。

PHPにはstdClassというビルトインクラスがありますが、これはJavaのObjectのような基底クラスというわけではなく、ただのクラスです。
基本的にユーザがstdClassを新規作成するようなことはあまりなく、[json_decode](http://php.net/manual/ja/function.json-decode.php)や[(object)キャスト](http://php.net/manual/ja/language.types.type-juggling.php#language.types.typecasting)などの結果として返ってくるものがほとんどです。

stdClassは[Iterableでもない](http://php.net/manual/ja/function.is-iterable.php)のにforeach可能なので、Iterableにしたほうが統一的なんじゃないかという主張でしたが却下されました。
[Internal](https://externals.io/message/103718)ではそもそもstdClassを使うな的方向に向かっててどうなんだ。

元々オブジェクトに対する繰り返しは[全ての可視プロパティが見れる](http://php.net/manual/ja/language.oop5.visibility.php)という仕様が先にあって、今でもPDOやらDateTimeやらIterableじゃないのにforeachできるクラスが山のようにあるので、今さらstdClassだけIterableにしたところで意味がない気がしてならない。


## [iterable_to_array() and iterable_count()](https://wiki.php.net/rfc/iterable_to_array-and-iterable_count)

iterable_to_arrayは賛成8、反対24で却下、iterable_countは賛成2、反対35で却下。

[iterator_to_array](http://php.net/manual/ja/function.iterator-to-array.php)なのに[Iterableを渡せない](https://qiita.com/suin/items/5f76a3eeaca70a5c3ba8)、どういうことだ、Iterableを配列にするメソッドがあってもいいはず、というRFCです。
任意のIterableを配列にするiterable_to_array、個数を数えるiterable_to_arrayが提案されましたが、両方とも却下されました。

まあ1行で書ける中身ですし、あと関数名が極めて誤認しやすいので、あると混乱しそうですね。

```php
function iterable_to_array(Iterable $iterable){
	return is_array($iterable) ? $iterable : iterator_to_array($iterable);
}
```


## [User-defined object comparison](https://wiki.php.net/rfc/object-comparison)

賛成5、反対12で却下。

オブジェクト同士の比較を独自に定義できるようにしよう、というRFC。
PHP以外の言語では大抵実装されているものです。

元々エクステンションでは[==の定義を変更できる](https://qiita.com/rana_kualu/items/129b4210ce99e7f50d06)のですが、PHPでも変更できるようにマジックメソッド`__compareTo`と`__equals`を追加します。

```php
class Example
{
    /**
     * <,>,<=>等による比較を行う
     * @param mixed 比較対象
     * @returns int $otherより大きければ1、小さければ-1、等しければ0
     */
    public function __compareTo($other): int
    {
        return $this <=> $other;
    }
 
    /**
     * ==による比較を行う
     * @param mixed 比較対象
     * @returns bool ==ならtrue
     */
    public function __equals($other): bool
    {
        return $this == $other;
    }
}
```

これによって、`==`、`!=`、`<`、`<=`などを独自に設定可能になります。

なお`===` `!==`の定義は変更できません。
こちらは定義が『同じインスタンス』なので、さすがに変更できてしまうと困りますからね。


## [Class Friendship](https://wiki.php.net/rfc/friend-classes)

賛成6、反対27で却下。

[こちらで解説](https://qiita.com/rana_kualu/items/64ce1e27a48005f96854#%E3%81%8A%E3%81%BE%E3%81%91)しています。
友達認定した相手は自分のprotectedやprivateを読めるようになる、というなかなか面白い機能です。

面白いだけで用途は一種類しか思いつきません。
テストクラスを指定することでリフレクション地獄を回避する、というものです。

でもこのRFCが通ったとして、PHPUnitからReflectionをなくせるかというとかなり非現実的な気がしますね。


## [Implement SQLite "openBlob" in PDO](https://wiki.php.net/rfc/implement_sqlite_openblob_in_pdo)

賛成7、反対7で却下。

[SQLite3::openBlob](http://php.net/manual/ja/sqlite3.openblob.php)がPDOの[SQLiteドライバ](http://php.net/manual/ja/ref.pdo-sqlite.php)に無いので追加してくれ、というRFC。

あんまりDB固有の機能までPDOで対応してしまうと今後ずっと面倒みないといけないからしない、とのことです。
そもそもBLOBをstreamで取得できるなんてこと自体知らなかったわい。


## [UUID](https://wiki.php.net/rfc/uuid)

賛成17、反対22で却下。

一意なグローバル識別子[UUID](https://ja.wikipedia.org/wiki/UUID)生成関数を追加しようというRFC。

却下の理由としては既に[PECL](https://pecl.php.net/package/uuid)や[Composer](https://packagist.org/packages/ramsey/uuid)による実装があるし、PHPコアで実装するほどのものではないだろう、理由がひとつ。
あとなんか[プルリク](https://github.com/php/php-src/pull/2535)がこれまであまり見たことない程度には紛糾していたので、そのせいかもあるかもしれません。

そんなことより[uniqid](https://secure.php.net/function.uniqid)の役立たなさをどうにかしてもらえないだろうか。

## [Unary null coalescing operator](https://wiki.php.net/rfc/unary_null_coalescing_operator)

賛成4、反対12で却下。

NULL合体単項演算子を導入しよう、という提案。

```php

if($id ?? === 1 ){
	// 何か
}

// ↓と同じ
if(isset($id) && $id === 1 ){
	// 何か
}
```

毎回`if( isset($_REQUEST['hoge']) && $_REQUEST['hoge'] === 'fuga' )`とか書くのは面倒なんじゃ、というのはPHPerなら誰しも考えることですが、しかし[RFCが間違ってるぞ](https://github.com/php/php-src/pull/2589)というツッコミを受けてあえなく撃沈。

RFCには`$_GET["action"] ?? NULL === "submit"`と`isset($_GET["action"]) && $_GET["action"] === "submit"`が同じと書いてあるのですが、実際は動作が異なります。
もう少し丁寧にRFCを推敲してから提出していたら結果も変わっていたかもしれませんね。


## [Doxygen](https://wiki.php.net/rfc/doxygen)

賛成11、反対16で却下。

ソースコードのドキュメントに[Doxygen](http://www.stack.nl/~dimitri/doxygen/)を導入しよう、という提案。
DoxygenはJavaDocに似た形式で、きちんと書かれたコメントから簡単にドキュメントを生成することができます。

自動生成ドキュメントをどこかに公開することで[マニュアル](http://php.net/manual/ja/index.php)よりも正確な情報を提供でき、ドキュメントであれば修正もたやすいのでソースコード変更への参入障壁も下がるからメンテナもきっと増えるぞと夢が広がりんぐ状態でしたが、[ML](https://externals.io/message/99140)では[昔やろうとしたけど諦めた](https://github.com/jgmdev/phoxygen)とか、[試しにやってみたけど死ぬわ](https://github.com/php/php-src/pull/2523/files)と評判は芳しくありませんでした。

まあ数千ある関数を今から対応していくのは並大抵の労力ではありませんしね。
最初から提唱者が1000個くらい対応したプルリクを送っていたら、満場一致で採択されたに違いありません。


## [Binary String Deprecation](https://wiki.php.net/rfc/binary_string_deprecation)

賛成19、反対13で却下。

バイナリ文字列を削除しよう、という提案。

PHPは[(binary)キャスト](http://php.net/manual/ja/language.types.type-juggling.php)をサポートしているのですが、実はこれ、[(string)キャストと全く同じ](https://github.com/php/php-src/blob/php-7.3.2/Zend/zend_language_scanner.l#L1483)です。

```c:zend_language_scanner.l
<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("string"|"binary"){TABS_AND_SPACES}")" {
	RETURN_TOKEN(T_STRING_CAST);
}
```

では何なのかというと、[PHP6で内部コードがUnicodeになったとき](https://externals.io/message/26562)のために用意されたもののようです。
しかしPHP6は頓挫したため、今となっては無用の長物です。

ということでRFCになりましたが、[将来また要るかもしれないだろ](https://externals.io/message/96743)ということで却下されました。
いや、どう考えても要らない子だろう。
要るかもしれないからやっておこう、というのは[全くの不要](https://qiita.com/rana_kualu/items/379eefb3a40c6b44cb92#8-%E4%B8%8D%E8%A6%81%E3%81%AA%E6%8B%A1%E5%BC%B5%E6%80%A7%E3%82%92%E7%9B%9B%E3%82%8A%E8%BE%BC%E3%82%80)です。


## [Throwable code's type generalization](https://wiki.php.net/rfc/throwable-code-generalization)

賛成13、反対11で却下。

[Exception::$code](http://php.net/manual/ja/class.exception.php)や[Throwable::getCode](http://php.net/manual/ja/throwable.getcode.php)はint型って書いてあるのに、[PDO](http://php.net/manual/ja/book.pdo.php)をはじめPHP自体がこれに多々違反してるんだが、という指摘。

実際にZend Frameworkで[PDOExceptionがstring返して来がやる](https://github.com/zendframework/zend-servicemanager/pull/167)といった実害も発生しています。

RFCは引数を`mixed`にしろという内容なので、逆に広くなりすぎて問題なので却下は妥当でしょう。
しかし実装が合ってないのももちろん問題なので、今後は実装を修正していくべきでしょう。


# 感想

うん、まあ、却下されて当然のRFCがほとんどという気がしてならない。
個人的には、採択したほうがよかったと感じるのはBinary String Deprecationくらいですかね。
Throwable code's type generalizationは実装をintに合わせるべきって主張なら受け入れられたかもしれない。