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

[その1](http://qiita.com/rana_kualu/items/644def9847b116c8f108) / [その2](http://qiita.com/rana_kualu/items/180990033bd9b1b2c316) / [その3](http://qiita.com/rana_kualu/items/09e85bf84175a9b82e11)

## Declined RFC

最近のPHPでは、新機能はまず[ML](http://marc.info/?l=php-internals)等にアイデアを出して[RFC](https://wiki.php.net/rfc)を作成し、投票において有権者の2/3の賛同を得て初めて導入されるという[流れ](https://wiki.php.net/rfc/howto)になっています。
その関門を通り抜けたものだけが[新機能としてデビュー](http://qiita.com/rana_kualu/items/572494021917fbb93c95)できるわけですが、中には当然却下されたものも存在します。

せっかくだから[却下されたRFC](https://wiki.php.net/rfc#declined)を、新しい順に10件見てみます(2016/08/09時点)。
今後通りやすいRFCを提案する際の参考になるかもしれません。
その2に続くかどうかは不明。


### [New operator for context-dependent escaping](https://wiki.php.net/rfc/escaping_operator)

賛成0/反対27で却下。

```php
<?* $str, 'html' ?>
<?= htmlspecialchars($str, ENT_QUOTES | ENT_HTML5 | ENT_DISALLOWED | ENT_SUBSTITUTE) ?>
```

が等しくなるという提案。

おいやめろ馬鹿と言わざるをえないRFCですが、さすがに皆そう思ったようで、圧倒的支持率で却下されました。
さらにset_escape_handler()で任意のエスケープを設定できるという構想もあったようですが、めでたく没となりました。


### [Enable session.use_strict_mode by default](https://wiki.php.net/rfc/session-use-strict-mode)

賛成4/反対4で却下。

session.use_strict_modeをデフォルトで有効にするという提案。

session_start()するとランダムなセッションIDがCookieに設定されますが、`PHPSESSID=hoge`みたいに書き換えてサイトにアクセスすると、PHPではその`hoge`というセッションIDでセッションが有効になります。
これは[セッション固定攻撃](http://bakera.jp/glossary/%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E5%9B%BA%E5%AE%9A%E6%94%BB%E6%92%83)という脆弱性に繋がるから、サーバ側で発行していないセッションIDは拒否しよう、というものです。

しかしそもそもsession.use_strict_modeを使う使わないに関わらず[正しいアプリの書き方は変わらない](http://www.slideshare.net/ockeghem/phpconf2013)という指摘もあり、互換性をわりかし優先するPHPの方針として却下されたのかもしれません。
このあたりは何年か前に[二人で延々殴り合ってた](https://www.google.co.jp/search?q=大垣+徳丸+session.use_strict_mode)ので追ってみると面白いかもしれません。


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

賛成4/反対15で却下。

[gettype()](https://secure.php.net/gettype)が返す型は、int型が'integer'、float型が'double'のように、型名と文字列が合ってない部分があるため、そこを合わせた関数を新設しようという提案。
あと何故かクローズした後のリソース型も取れるようになります。

```php
$fh = tmpfile();
fclose($fh);
var_dump(gettype($fh)); // 'unknown type'
var_dump(var_type($fh)); // 'resource'
```

それだけしか変わらないのにわざわざ関数を増やす意義はないだろうということで却下。
さらに定数TYPE_**を導入するという提案に至っては1対21で反対多数となりました。
そもそもgettype()自体普通使わないよね。


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

賛成0/反対25で却下。

var_type()のさらに値の概要についても表示しよう、という提案。
こんなの実装されたところで全く使い道がないので却下。


### [ReflectionTypeImprovements](https://wiki.php.net/rfc/reflectiontypeimprovements)

賛成5/反対8で却下。

PHP7で[ReflectionType](http://php.net/manual/ja/class.reflectiontype.php)が導入されましたが、allowsNull()、isBuiltin()、__toString()と最低限の機能しか実装されていません。
ここにReflectionNamedType::getName()とReflectionClassType::getClass()を追加しましょうという提案。

なんだけど、これ、いちいちクラス分けずにReflectionType::getName()とgetClass()を追加するだけでは駄目なのか？


### [Typed Properties](https://wiki.php.net/rfc/typed-properties)

賛成34/反対23で却下。

```php
class Foo {
  public int $int = 1;
  public float $flt = 2.2;
  public array $arr = [];
  public bool $bool = false;
  public string $string;
  public callable $callable;
  public stdClass $std;
  public OtherThing $other;
  public $mixed;
}
```

今回調査した中で、唯一賛成多数で却下された項目。
内容は一目瞭然で、プロパティの型指定です。
[HHVM](https://docs.hhvm.com/hack/types/type-system)から逆輸入したような形です。
これが通ればもう他言語に大きな顔をされることもないだろう大きな提案だったのですが、何故か却下されました。
引数型指定があるんだから、もうプロパティ型指定くらいあってもいいじゃない。
処理速度が2割も落ちるというデメリットがあるらしいので、そのあたりでノーを突きつけられたのかもしれません。
いやでも、この機能はほんと欲しかったですね。


### [Union Types](https://wiki.php.net/rfc/union_types)

賛成5/反対23で却下。

```php
function hoge(array | string $arg): int | bool{
	// $argはarrayかstring
	// returnはintかbool
	return 1;
}
hoge([]); // OK
hoge('1'); // OK
hoge(1);  // NG
```

[Multi Catch](https://wiki.php.net/rfc/multiple-catch)は受理されましたが、こちらは拒否されました。
まあ、こんなの認めたら型引数の意味がなくなっちゃいますからね。


### [Callable prototypes](https://wiki.php.net/rfc/callable-types)

賛成18/反対19で却下。

引数の[callable](http://php.net/manual/ja/language.types.callable.php)の引数の型を指定したい。

```php
function foo(int $i, callable $f):int{
	return $f($i);
}
echo foo(1, function($x){return $x;});
echo foo(1, function(){return 2;});
```

2回目のcallableは引数$iを受け取らないので、想定した使い方ではありません。

```php
function foo(int $i, callable(int):int $f):int{
	return $f($i);
}
echo foo(1, function(){return 2;}); // Uncaught TypeError
```

これでfoo()の引数のcallableの引数の型を指定できました。

さらに今後は名前付き型引数までをも想定していたようです。

```php
callable NamedCallableType(int $a, int $b): bool;
function foo(NamedCallableType $f){}
function bar(NamedCallableType $f){}

foo(function(int $a, int $b){ return $a>$b; });
```

[Python](https://www.python.org/dev/peps/pep-0484/#callable)や[Rust](https://doc.rust-lang.org/book/closures.html#taking-closures-as-arguments)など他言語に実装されている機能の輸入のようです。
互換性の破壊は一切無いしで一見悪くなさそうなのですが、過半数の反対で却下されました。
改修規模のわりに効果が限定的だからでしょうか。


### [Functional Interfaces](https://wiki.php.net/rfc/functional-interfaces)

賛成7/反対22で却下。

SAMインターフェイスを関数からimplementsしたい。

```php
interface IFoo {
    public function method() : int;
}
 
$cb = function () implements IFoo : int {
    return 42; // IFoo::method()の実装
};
```

SAMとはSingle Abstract Method、つまりSAMインターフェイスは未実装メソッドをひとつしか持たないインターフェイスのことです。
で、クロージャに直接SAMインターフェイスをimplementsしたら、自動的にそのメソッドの実装となると。
Javaの関数型インターフェースみたいなものです、というかそのもの？

```php
$f = function() implements IteratorAggregate{
  return new ArrayIterator([1,2,3]); // IteratorAggregate::getIterator()の実装
};
```

CountableやIteratorAggregateを明示できるのは多少は便利かもしれません。
なおTraversableにはメソッドが無い、Iteratorは5個もあるのでSAMではない、ということでそれらはimplementsできません。


### [PHP Attributes](https://wiki.php.net/rfc/attributes)

賛成14/反対22で却下。

PHPでアノテーションを使えるようにする提案。

```php
<<WithoutValue, SingleValue(0), FewValues('Hello', 'World')>>
function foo() {}
```

Javaのアノテーションは@ですが、PHPの場合エラー制御演算子と区別が付かないので<<>>になっています。
ただこのせいで、過去のPHPとは完全に互換性が切れてしまいます。
この一点だけでも導入はほぼ不可能と言っていいでしょう。
せめて旧バージョンではコメント形式になるとかできなかったのでしょうか。

あと@Overrideとか@paramとかのよく使うアノテーションの書き方がよくわからなかった。


## まとめ

思いつきレベルのRFCも意外とある。
逆に、RFCをしっかり書いてパッチまで作ったとしてもRejectされることも普通にある。
どちらかというと有権者への根回しのほうが有効かもしれない。