最近提出されたPHP RFC

ここ最近提出された[PHP RFC](https://wiki.php.net/rfc)をなんとなく新しい順に見てみました。
これらは将来のPHPに確実に実装されるというわけではなく、[却下](https://qiita.com/rana_kualu/items/644def9847b116c8f108)されることも十分にありえます。
というか見た感じ半分以上却下されるんじゃないかしら。

# RFC

日付はRFCのDateに書かれてるものですが、これが提出日なのか更新日なのか何かの記念日なのかわからない。
そもそもRFCの並び順が新しい順とかじゃなくて適当なんだけどなにこれ。


## [Immutable classes and properties](https://wiki.php.net/rfc/immutability)

2018/02/19提出。
新たなキーワードimmutableをくれ、という提案。

```php
	immutable class Foo {
	  public $email;
	  public function __construct($email) {
	    $this->email = $email;
	  }
	}

	// コンストラクタ以外では変更不可
	$email = new Foo("foo@example.com"); // OK
	$email->email = "bar@example.com" // Fatal Error

	// extendsも不可
	class Bar extends Foo{} // Fatal Error
```

immutableなクラスは、インスタンス作成時のコンストラクタ以外での内部プロパティ変更が不可能になります。

プロパティにもimmutableを指定できます。

```php
	class A {
	  public immutable $x;
	  public $y;
	  public function __construct($x, $y = null){
	    $this->x = $x;
	    $this->y = $y;
	  }
	}

	// $xはコンストラクタ以外では変更不可
	$a = new A(1, 2);
	$a->x = 3; // Fatal Error
	$a->y = 4; // こちらはOK

	// immutableでない型は渡せない
	new A('text'); // OK
	new A(new Foo()); // むしろimmutableなクラスはimmutableプロパティでないと駄目
	new A([]); // Fatal Error 配列はNG
	new A(fopen('hoge.txt', 'r')); // Fatal Error リソースも不可
```

niigataアクセス修飾子！niigataアクセス修飾子じゃないか！

しかしリソースはまだしも配列が駄目というあたりがやな感じである。
それ以前にそもそもPHPにimmutableなんて必要なのかね、と思わないでもないんだけど、そういえば[DateTimeImmutable](http://php.net/manual/ja/class.datetimeimmutable.php)がないと生きていけないんだった。


## [Deprecate backtick operator](https://wiki.php.net/rfc/deprecate-backtick-operator)

2018/02/11提出。
バッククォート`をDeprecatedにしようという提案。

バッククォートは[shell_exec](http://php.net/manual/ja/function.shell-exec.php)と等価で、いきなりソースに書かれてたりするとわかりにくいことこの上ないので、個人的には正直要らないと思うのですが、[フォーラム](https://externals.io/message/101823)を見るかぎり否定派が多そうです。
先に削除するのは`@`だろう、とか。
というか提案者の話し方がちょっと微妙というか説得させる気がとても感じられない。
おそらく却下されるんじゃないかな。


## [Argon2 Password Hash Enhancements](https://wiki.php.net/rfc/argon2_password_hash_enhancements)

2018/01/11提出。
Argon2idの実装提案。

PHP5.5で[password_hash](https://qiita.com/rana_kualu/items/3ef57485be1103362f56)という超絶便利関数が実装されました。
PHP7.2現在では、この関数で使用できるハッシュアルゴリズムはPASSWORD_BCRYPTとPASSWORD_ARGON2Iの2種類だけです。

Argon2は[環境に応じて暗号強度を変えられる](http://php.net/manual/ja/password.constants.php)というハッシュアルゴリズムで、現在3種類のバージョンが存在します。
Argon2dはGPUクラッキング耐性を重視したアルゴリズムで、Argon2iはタイミング攻撃などのサイドチャネル攻撃に強くなるようデザインされたアルゴリズムです。
弱点はそれぞれ反対で、Argon2dはサイドチャネル攻撃に弱く、Argon2iはGPUクラッキング攻撃に弱くなります。
PHPに実装されているのはArgon2iです。

両者のいいとこ取りをした第三のアルゴリズムArgon2idというものがあるので、次バージョンでそのハッシュアルゴリズムPASSWORD_ARGON2IDを追加しようという提案です。
そんな便利なアルゴリズムがあるなら何故[最初](https://wiki.php.net/rfc/argon2_password_hash)から導入しなかったのかというと、当時はまだArgon2idの仕様が固まってなかったからのようです。
[別記事でも書いた](https://qiita.com/rana_kualu/items/3ef57485be1103362f56)ように、password_*関数はアルゴリズムの変更がきわめて容易なので、さくっと対応してもらえるといいですね。


## [Scalar Pseudo-type](https://wiki.php.net/rfc/scalar-pseudo-type)

2017/12/24提出。
スカラー疑似型がほしい、という提案。

[is_scalar](https://secure.php.net/is-scalar)という関数は昔からあるものの、対応する型は実は今まで存在しませんでした。
そこで対応する疑似型を作りましょう。

```php
	
	// scalar疑似型
	function f1(scalar $param) :scalar{
	    return $param;
	}
	
	f1(1); // OK
	f1(null); // NG
	
	// scalar疑似型のイメージ
	function f2(bool | float | int | string $param) :bool | float | int | string {
	    return $param;
	}
	
	// NULL許容scalar疑似型
	function f3(?scalar $param) {
	    echo "{$param}\n";
	}
	
	f3(null); // OK
	f3(); // NG
```

いやあ、そもそも引数をもっと厳格にしろ、と言いたい。
bool | float | int | stringが返ってくる関数とか半端すぎて使い道に困るだろ。


## [Explicit call-site pass-by-reference](https://wiki.php.net/rfc/explicit_send_by_ref)

2017/12/02提出。
参照渡し関数は呼び出し側に`&`を付けられるようにしよう、という提案。

```php
	function inc(&$num) { $num++; }

	$i = 0;
	inc(&$i);
	var_dump($i); // int(1)
```

見える、PHP4時代の老兵が錯乱する様が見えるぞ。

しかし、これはかつての『呼び出し側に&を付けるだけで参照渡しになる』機能とは異なります。
関数が既に参照渡しである場合にかぎり&を付けてもエラーにならないようにする、というだけの内容です。

```php
	// 普通の関数は呼び出しに&を付けられない
	function inc2($num) { return $num+1; }
	
	inc(&$i); // Cannot pass reference to by-value parameter 1
```

参照渡し問題に対する根本的かつ唯一の解は、参照渡しを一切使用しないことです。
PHPに参照渡しなど不要。

と言いたいところなのですが、実はそうもいかない問題があるのです。
そもそも何故このような提案が出てきたかというと、たとえば以下です。

```php
	$ret = array_slice($array, 0, 3);
	$ret = array_splice($array, 0, 3);
```

これを見て`$array`がどうなるかわかる人は変態だけです。

```php
	$ret = array_slice($array, 0, 3);
	$ret = array_splice(&$array, 0, 3);
```

こう書けば、どうなるか多少わかりやすくなります。

なお、この記述はあくまでオプションで、これまでのように付けなくても動作します。

機能的にはよい内容だと思うのですが、問題はこれが書かれたソースを見たときにうっかり「こんな古生代の書き方した奴は誰だ！」とか思ってしまいそうなところでしょうか。


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

2017/09/13提出。
軽量な実行スレッドFiberを導入しようという提案。

```php
	function sub1(){
		return Fiber::yield(1);
	}
	
	$fiber = new Fiber(function ($a, $b) {
		$c = Fiber::yield($a + $b);
		$d = sub1();
		return $d.$c;
	});
	
	echo $fiber->resume(1, 2);     // echo 3
	echo $fiber->resume("world");  // echo 1
	echo $fiber->resume("hello "); // echo "hello world"
```

`yield`で処理を中断し、`resume`でその続きから実行する、ということでRubyのFiberやLuaのコルーチンと同じものです。
しかし[Generator](http://php.net/manual/ja/language.generators.syntax.php)とどう違うのか正直よくわからない。
別関数を`yield from`って呼ばなくてよくなったくらい？


## [Operator functions](https://wiki.php.net/rfc/operator_functions)

2017/09/08提出。
関数を渡す関数に演算子を渡したいという要望。

```php
	// 配列を全部足す
	$arr = [1, 3, 5];
	$sum = array_reduce($arr, function($a, $b){return $a+$b;});
	
	// こう書ける
	$sum = array_reduce($arr, '+');
```

この場合は`array_sum`でいいんだけど、そういう特殊な関数ではなく汎用的なところで便利になる場合が…

```php
	usort($data, '<=>'); // sort() と同じ
	'**'(5, 8);          // 5**8 と同じ
	'||'($a, $b);        // $a || $b と同じ
```

要るかこの機能？
`'||'($a, $b, $c, $d)`とか書けるならもしかしたらワンチャン？

演算子を関数として扱えるようになるということなので、今後はユーザ定義演算子を追加するようなことも考えているようです。
もしかしたら`runkit_operator_redefine()`みたいなものも現れるかもしれませんね。
是非辞めていただきたい。


## [Mixed typehint](https://wiki.php.net/rfc/mixed-typehint)

2017/07/19提出。
疑似型mixedがほしい、という提案。

```php
	function foo(mixed $arg): mixed {
	    return $arg;
	}
```

これならまだscalarn疑似型のほうがマシだよ。
こんなもん却下だ却下。


## [Deprecate PDO::PARAM_NULL](https://wiki.php.net/rfc/deprecate_pdo_null)

2017/05/15提出。
[PDO::PARAM_NULL](http://php.net/manual/ja/pdo.constants.php)っていらなくね？

```php
	// 現在
	$statement->bindValue(1, null, PDO::PARAM_NULL);
	
	// 変更後
	$statement->bindValue(1, null);
```

そもそもSQL標準には、nullを許容する型はあれど、null型という型はないので、NULLデータ型という定義自体がおかしいです。
さらに現状のPDOドライバは引数がnullだったらPDO::PARAM_*を気にせず値がnullになるので、実用上も問題ありません。
ということで削除しましょう。


## [Deprecation of fallback to root scope](https://wiki.php.net/rfc/fallback-to-root-scope-deprecation)

2017/03/05提出。
グローバル空間へのフォールバックをやめよう。

```php
	namespace Bar;
	strlen();
```

この[strlen](http://php.net/manual/ja/function.strlen.php)はまず`\Bar\strlen()`を探し、それが存在しなければ`\strlen()`を見に行きます。
この機能のおかげでPHPの標準関数は全てグローバルに使用することができるわけです。

実はこの機能のせいで、途中で関数定義が変わってしまう場合があります。

```php
	namespace foo{
	    $t = 'テキスト';
	    echo strlen($t);
	    echo strlen($t);
	    if(true){ function strlen($t){return mb_strlen($t);} }
	    echo strlen($t);
	    echo strlen($t);
	}
```

上2つのstrlenは`\strlen()`を、下2つのstrlenは`\foo\strlen()`を[呼び出します](https://3v4l.org/onORD)。
意図せず[runkit_function_redefine](http://php.net/manual/ja/function.runkit-function-redefine.php)のようなことが起こってしまいました。

といっていきなりフォールバックを禁止すると死者が続出するので、このRFCではE_NOTICEを出すだけにしておいて、次のバージョンで削除する予定のようです。
しかし、この提案はさすがにちょっと影響範囲が大きすぎるので、そう簡単には受け入れられないんじゃないかなと思います。
[フォーラム](https://externals.io/message/101745)では「こんなん実装したらみんなエラーメッセージの海に埋もれて死ぬわ」とか言われてます。


## [Arrow Functions](https://wiki.php.net/rfc/arrow_functions)

2016/08/14提出。
これは少し古いけど興味深かったので。

```php
	// $x*2を返す関数
	$mul2 = fn($x) => $x * 2;
	
	$mul2(3); // 6
```

なんかすごい何処かで見たことのあるような構文だな。

```php
	// $versionAと$versionBは同じ
	$y = 1;
	$versionA = fn($x) => $x + $y; // $yが見える

	$versionB = function ($x) use ($y) {
	    return $x + $y;
	};
	
	// $extended1と$extended2は同じ
	$extended1 = function ($c) use ($callable, $factory) {
	    return $callable($factory($c), $c);
	};
	
	$extended2 = fn($c) => $callable($factory($c), $c); // $callableや$factoryが見える
```

文法そのものは悪くないんじゃないかと思いますが、スコープを無視して変数が見えるのはとても気持ち悪いです。
実はこれ[元ネタ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/arrow_functions)から存在している仕様なのですが、だからといってわざわざ汚点まで持ってくる必要はないでしょう。

```js:JavaScript
	var f = (x) => { return x + y; };
	f(1); // Uncaught ReferenceError: y is not defined
	
	y=5;
	f(1); // 6
```

# 感想

ジェネレータや可変長引数、戻り値型宣言のような心躍る新機能がいまいち見当たらない。
Arrow Functionsは面白そうだけど、採用されそうな気が全くしないのは何故だろう。

ところでいつも思うんだけど、無名関数ってどうせconstとかに突っ込むんだから結局名前あるよね(関係ない)