PHP RFCがたくさん投票中

やたらめったら腰が重いことで有名な[PHP RFC](https://wiki.php.net/rfc)ですが、なんとなく覗いてみたら突然6個のRFCが投票フェーズに入ってました。
今までせいぜい2個くらいしか見たことなかったのでびっくりだよ。

せっかくなので現在投票中のRFCを見てみます。
みんなも投票に参加してみよう。
なお、賛成反対数は2018/07/12時点での数です。

# In voting phase

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

ユーザ定義のオブジェクトで比較を定義できるようにしようというRFCです。
[オブジェクトの比較](http://php.net/manual/ja/language.oop5.object-comparison.php)は、現在の仕様では、
・`==`は同じクラスのインスタンスであればtrue
・`===`は同じインスタンスであればtrue
[となっています](https://3v4l.org/Fkh1J)。

```php
	$a = new \stdClass();
	$b = $a;
	$c = clone $a;
	
	var_dump($a==$b, $a===$b); // true, true
	var_dump($a==$c, $a===$c); // true, false
```

また不等号については明文化されていませんが、プロパティを順に見ていって最初に見つかった異なる値を比較するという、わりかし[微妙な実装](https://3v4l.org/TCrTW)になっています。

```php
class HOGE{
	private $a;
	private $b;
	public function __construct($a, $b){
		$this->a = $a;
		$this->b = $b;
	}
}

$a = new HOGE(10, 20);
$b = new HOGE(10, 30);
$c = new HOGE(11, 0);

var_dump($a>$b, $a<$b); // false, true 20<30
var_dump($a>$c, $a<$c); // false, true 10<11
var_dump($b>$c, $b<$c); // false, true 10<11
```

異なるオブジェクト同士の比較は基本的にfalseですが、宇宙船演算子は[何故か1](https://3v4l.org/f8qO1)になります。

```php
	$a = new \stdClass();
	$b = new \DateTime();
	
	var_dump( $a == $b, $a < $b, $a > $b ); // false, false, false
	var_dump( $a <=> $b ); // 1 ←？
```

日時クラスなど任意に大小比較を行いたいクラスはこのような仕様では困るので、独自の比較を行えるマジックメソッド`__compareTo`と`__equals`を追加しよう、という提案がされました。

```php
class Example{
	/**
	* $a < $bであれば$a::__compareToが呼ばれて引数は$bになる
	* @param mixed 右辺
	* @return int 左辺が大きいなら1、小さいなら-1、等しいなら0
	*/
    public function __compareTo($other): int{
    	return $this <=> $other;
    }

	/**
	* 緩い比較`==`で呼ばれる
	* @param mixed 右辺
	* @return boolean $a == $bならtrueを返す
	*/
    public function __equals($other): bool{
        return $this == $other;
    }
}
```

これによって`<`、`<=`、`>`、`>=`、`==`、`!=`、`<=>`の挙動を操作することができるようになります。
`===`は同じインスタンスか否かなので変更の余地なしです。

これによって例えば`new \Metre(1) == new \Centimetre(100)`がtrueになったり、`new \Yen(10000) < new \Dollar(100)`みたいな比較ができるようになります。
できるようになるといっても実際書いてみるとちょっと気持ち悪いので、普及するかは微妙な気がしますが。

2018/07/16まで投票中、賛成4反対11でおそらく却下されます。¯\_(ツ)_/¯


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

PHP7.1で[型宣言Iterable](https://qiita.com/rana_kualu/items/572494021917fbb93c95#iterable)が追加されました。
これによって配列とイテレータをひとまとまりで操作できるようになりました。

しかし配列関数を使いたい場合など、うっかりイテレータをarray関数に突っ込むと死にます。
そこでIterableを安全に配列にするiterable_to_array関数を追加しましょう。

```php
	// Iterableを配列にする
	$array = iterable_to_array($iterable);
	// これと同じ
	$array = is_array($iterable) ?: iterator_to_array($iterable);
	
	// Iterableの個数を求める
	$count = iterable_count($iterable);
	// これと同じ
	$count = is_array($iterable) ? count($iterable) : iterator_count($iterable);
```

いや、要らんだろこれ。

2018/07/16まで投票中、賛成8反対20でおそらく却下されます。


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

protectedなメソッドとプロパティは、本来は自身か自身をextendしたクラスからしかアクセスすることはできません。
Class Friendshipは、友達には自分のprotectedを見せてもいいようにしようというRFCです。
元ネタのC++では[privateにもアクセスできる](https://msdn.microsoft.com/ja-jp/library/465sdshe.aspx)のですが、[議論の結果](https://marc.info/?l=php-internals&m=144972388219786&w=2)PHPではprotectedだけになったようです。

```php

class A{
	friend B;
	
	protected $trueName = 'AAA';
	
	public function getBsTrueName(B $b){
		return $b->trueName;
	}
}

class B{
	protected $trueName = 'BBB';
	
	public function getAsTrueName(A $a){
		return $a->trueName;
	}
}

$a = new A();
$b = new B();

$b->getAsTrueName($a); // AAA
$a->getBsTrueName($b); // Fatal Error: Cannot access protected property
```

AはBのことを友達だと思っているのでBはA::trueNameが読めます。
BはAのことを友達だと思っていないのでAはB::trueNameを見ることができません。

これができて何がうれしいかというと、なんといってもテスト開発者ですね。
PHPUnitとかとにかくひたすらReflection山盛りですから、ここを「friendって書いとけ」で終わらせられるのは楽そうです。
普通の開発者にはあまり恩恵はなさそうです。


2018/07/13まで投票中、賛成6反対25でおそらく却下されます。


## [Deprecations for PHP 7.3](https://wiki.php.net/rfc/deprecations_php_7_3)

古い機能がDeprecateになり、PHP8で削除されます。

### Undocumented mbstring function aliases

`mbereg_search_getpos`って関数知ってる人いるでしょうか。
これは[mb_ereg_search_getpos](http://php.net/manual/ja/function.mb-ereg-search-getpos.php)のエイリアスで、実は`mb_ereg**`関数には全て`mbereg_**`というエイリアスが用意されています。
これらは一切ドキュメント化されていないし、意味もないので削除しましょう。

2018/07/16まで投票中、賛成34、反対1でおそらく受理されます。

### String search functions with integer needle

[strpos](http://php.net/manual/ja/function.strpos.php)や[strstr](http://php.net/manual/ja/function.strstr.php)などの検索対象文字列に数値を与えると、[コードポイントとして解釈](https://3v4l.org/O9dmi)されます。

```php
	$str = "There are 97 apples";
	var_dump(strpos($str, "97")); // 10
	var_dump(strpos($str, 97));   // 6
```

あまりにわかりにくすぎるのでコードポイントの解釈をやめます。
PHP7.3でDeprecateとし、PHP8では単純に文字列として扱います。

2018/07/16まで投票中、賛成29、反対1でおそらく受理されます。


### fgetss() function and string.strip_tags filter

[fgetss](http://php.net/manual/ja/function.fgetss.php)という関数が……誰も知らないだろこんな関数。
[fgets](http://php.net/manual/ja/function.fgets.php)したあと[strip_tags](http://php.net/manual/ja/function.strip-tags.php)するという、誰得にも程がある関数です。
そもそもstrip_tags自体、多くのバグや機能自体の限界から運用に耐えられるようなものではなくなっています。
ということでfgetss、[gzgetss](http://php.net/manual/ja/function.gzgetss.php)、[SplFileObject::fgetss](http://php.net/manual/ja/splfileobject.fgetss.php)、[string.strip_tagsストリームフィルタ](http://php.net/manual/ja/filters.string.php#example-6800)をPHP7.3でDeprecate、PHP8で削除します。

2018/07/16まで投票中、賛成18、反対4でおそらく受理されます。


### Defining a free-standing assert() function

[assert](http://php.net/manual/ja/function.assert.php)はPHP7から言語構造となり、ノーコストで呼び出しができるようになりました。
`zend.assertions=-1`をセットすると完全に無視されます。

この設定、実は[グローバルでないassert関数も影響を受け](https://bugs.php.net/bug.php?id=75445)ます。

```php
namespace TEST{
	function assert(){
		throw new \Exception('hoge');
	}
	assert(1==1);
}
```

`zend.assertions=1`であれば`Uncaught Exception: hoge`が発生しますが、-1のときは何も起こりません。

そこでPHP7.3ではassert関数定義をDeprecateとし、PHP8では関数定義自体を禁止します。
`$this`並のアンタッチャブルになるようです。
独自のassert関数を定義したい場合は[assert_options](http://php.net/manual/ja/function.assert-options.php)を使いましょう。

なおassertメソッドは問題なく定義可能です。

2018/07/16まで投票中、賛成19、反対7でおそらく受理されます。


### FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED flags

[検証フィルタ](http://php.net/manual/ja/filter.filters.validate.php)のFILTER_VALIDATE_URLフィルタに、FILTER_FLAG_SCHEME_REQUIREDとFILTER_FLAG_HOST_REQUIREDというフラグがあります。

実はこのふたつ、FILTER_VALIDATE_URLフィルタにデフォルトで入っている上に無効化する方法がありません。
それなのにこのようなフラグが存在することによって、[正しいURLをネガティブ判定する](https://bugs.php.net/bug.php?id=72301)うえに[デフォルトでは入ってないと勘違いする](https://stackoverflow.com/questions/45240033/what-is-use-of-filter-flag-scheme-required-and-filter-flag-host-required-flags-f/45240693)ようなことになり、良くありません。

そこでPHP7.3でこれらをDeprecateとし、PHP8で削除します。

2018/07/16まで投票中、賛成30、反対0でおそらく受理されます。


### pdo_odbc.db2_instance_name php.ini directive


[pdo_odbc.db2_instance_name](http://php.net/manual/ja/ref.pdo-odbc.php#ini.pdo-odbc.db2-instance-name)はPHP5.1.1で実装されたものの当時からずっと非推奨のままでした。
これはDB接続用の設定にもかかわらずグローバルで定義されるため、全てのDB接続設定がプロセス全体で書き換えられてしまいます。

そこでPHP7.3でこの設定をDeprecateとします。PHP8で削除とは書かれていません。

2018/07/16まで投票中、賛成28、反対0でおそらく受理されます。


## [Deprecate and Remove Case-Insensitive Constants](https://wiki.php.net/rfc/case_insensitive_constant_deprecation)

PHPの定数は大文字で書くのが一般的ですが、別に小文字でも書けます。
それはいいのですが、[define](http://php.net/manual/ja/function.define.php)には大文字小文字を区別しないという謎すぎるオプションが存在します。
これを使うと簡単に[定数定義変更](https://3v4l.org/cDPO1)できます。

```php
define('hoge', 1, true);
var_dump(HOGE); // 1
define('HOGE', 2);
var_dump(HOGE); // 2
```

誰も得しないし実装も大変だしとてもよろしくないので、PHP7.3でこれらをDeprecateとし、PHP8でdefineの第三引数を削除します。

2018/07/16まで投票中、賛成34、反対0でおそらく受理されます。


## [array_key_first(), array_key_last() and array_value_first(), array_value_last()](https://wiki.php.net/rfc/array_key_first_last)

先日紹介した[配列の最後を求めるRFC](https://qiita.com/rana_kualu/items/a80ef40547496192de86)です。

2018/07/16まで投票中。
array_key_first/lastは賛成17、反対11でおそらく受理されます。
array_value_first/lastは賛成14、反対13で拮抗しています。


# PHP 7.3 Implemented

[PHP7.3の新機能](https://qiita.com/rana_kualu/items/a7c6be77e165bca0f3fc)以降、早くも3個のRFCが受理されていたので、ついでに紹介してみます。

## [Make compact function reports undefined passed variables](https://wiki.php.net/rfc/compact)

賛成32、反対5で受理されました。

[compact](http://php.net/manual/ja/function.compact.php)関数は、引数の変数名が存在しない場合、単に無視されます。

```php
$array = compact('hoge'); // 何も起こらない
var_dump($array); // []
```

失敗したかどうかわかりにくいため、今後は存在しない変数名を渡された場合にE_WARININGが発生するようになります。

ちなみに、どうして無視する実装になっていたのかは、誰にもわからなかったらしいです。


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

賛成17、反対0で受理されました。

[最近提出されたPHP RFC](https://qiita.com/rana_kualu/items/724958767d80b3729e52#argon2-password-hash-enhancements)で紹介した、password_hash関数のアルゴリズムを追加するRFCです。


## [Deprecate and Remove image2wbmp](https://wiki.php.net/rfc/image2wbmp)

賛成14、反対0で受理されました。

GDのWBMP出力関数は[image2wbmp](http://php.net/manual/ja/function.image2wbmp.php)と[imagewbmp](http://php.net/manual/ja/function.imagewbmp.php)の2種類があります。
元々は異なる処理をしていたらしいのですが、PHP5.0.0以降は実質的に同じようです。
そのためimage2wbmpを削除し、imagewbmpに統一します。

といってもwbmp自体、使っている人がいるのか怪しいものですが。


# 感想

投票フェーズまで進むRFCは、これまでは数ヶ月にひとつとかそういうレベルだったのに、いきなり何かあったのでしょうかね？
とはいえ受理されそうなのは削除されて当然な謎機能ばかりで、使えそうなのはarray_key_first/lastくらいなのが残念。

他にも[Distrust SHA-1](https://wiki.php.net/rfc/distrust-sha1-certificates)とか[Throw Exception on Attempt of Constant Redefinition](https://wiki.php.net/rfc/constant_redefinition)とか、速攻受け入れるべきRFCも色々あるので、今後も足を止めずにどんどん活動してほしいものですね。