PHP7.1β1の新機能

[PHP7.1.0の新機能](http://qiita.com/rana_kualu/items/f8baf30752928346bef8) / [PHP7.1β1の新機能](http://qiita.com/rana_kualu/items/572494021917fbb93c95) / [PHP7.1α1の新機能](http://qiita.com/rana_kualu/items/476385b674d27339f911) / [PHP7.0.0α1](http://qiita.com/rana_kualu/items/447995347acb2f8997a3) / [PHP5.6](http://qiita.com/rana_kualu/items/206d786a2be7942c6dc3)


PHP7.1はどういうわけか新機能をえらい盛り盛りしてきています。

前[PHP7.1の新機能](http://qiita.com/rana_kualu/items/476385b674d27339f911)というのを書きましたが、その記事はα1時点のものでした。
α2、α3、β1でさらに色々追加されていたので見てみます。


## [Replace "Missing argument" warning with "Too few arguments" exception](https://wiki.php.net/rfc/too_few_args)

```php
	function foo($a){}
	
	foo(); // Fatal error: Uncaught Error: Too few arguments to function foo()
	foo(null); // OK
```

デフォルト値の無い引数を省略した場合、これまではE_WARNINGが出るだけでしたが、今後はErrorになります。
不要な場合は引数にnullでも埋めておきましょう。

それにしても何故Errorなのか。
まだIllegalArgumentExceptionのほうが近くない？


## [Fix inconsistent behavior of $this variable](https://wiki.php.net/rfc/this_var)

```php
	class HOGE{
	    public function change($target){
	        $$target = new stdClass;
	    }
	}
	(new HOGE())->change('this'); // Fatal error: Uncaught Error: Cannot re-assign $this

	var_dump($this); // Fatal error: Uncaught Error: Using $this when not in object context
```

これまで裏技として使用可能だった[可変変数による$thisの再定義](http://qiita.com/rana_kualu/items/84ab2f596a21d0c972b8)がついに禁止されました。
α2以降Errorが発生します。
他に関数の引数やextract、globalといった、これまで存在していた抜け道も悉く潰されました。

さらにオブジェクトの外で`$this`を使った場合、これまではただのUndefined variableのE_NOTICEでしたが、α2以降はErrorが発生します。
今後$thisはオブジェクト内でしか使用できません。


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

型宣言iterableが追加されました。

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

	foo([1]);
	foo(new ArrayIterator([1]));
	foo((function(){yield 1;})());
	foo(null); // Fatal error: Uncaught TypeError: Argument 1 passed to foo() must be iterable

	var_dump(is_iterable([1])); // true
	var_dump(is_iterable(new ArrayIterator([1]))); // true
	var_dump(is_iterable((function(){yield 1;})())); // true
	var_dump(is_iterable(null)); // false
```

既に[Traversableインターフェイス](http://php.net/manual/ja/class.traversable.php)が存在するのに何故新しくiterableなんてものを作ったかというと、配列はTraversableではないからです。
iterableと書くことで、配列を含めたあらゆる反復可能オブジェクトを受け取ることが可能になります。

また、それに伴い関数is_iterable()が追加されました。
文字どおりiterableか否かを判定する関数です。


## [Nullable Types](https://wiki.php.net/rfc/nullable_types)

```php
	function bar(?iterable $iterable): ?int{
		return 1; // OK
		return null; // OK!
		return ''; // Uncaught TypeError: Return value of bar() must be of the type integer
	}

	bar([1]); // OK
	bar(null); // OK!
	bar(1); // Uncaught TypeError: Argument 1 passed to bar() must be iterable
```

引数および返り値の型宣言に?を付けると、引数にNULLを許容します。
元々この引数の部分は、Javaは何もせずともNULLを許容するのにPHPは禁止になっているという、珍しく厳格さが逆転していた点ですが、これでJavaと同じ使い方ができるようになります。
まあ、ぬるぽの大海原に乗り出していくことになるので、使用はあまりお薦めできないですが。


## [Closure from callable function](https://wiki.php.net/rfc/closurefromcallable)

コールバック関数からClosureを作成できる。

```php
	$f = (function(){
		return Closure::fromCallable(
			function($bar){
				var_dump($bar);
			}
		);
	})();

	$f(1); // 1
	$f('a'); // a
```

実はClosureよくわからないんですよね。
そもそも↑はいったい何の役に立つのか。


## [Add curl_multi_errno(), curl_share_errno() and curl_share_strerror()](https://wiki.php.net/rfc/new-curl-error-functions)

cURLには[通常のcURLハンドル](http://php.net/manual/ja/function.curl-init.php)、[cURLマルチハンドル](http://php.net/manual/ja/function.curl-multi-init.php)、[cURL共有ハンドル](http://php.net/manual/ja/function.curl-share-init.php)がありました。

通常ハンドルではcurl_errno()でエラー番号を取得できるのにマルチハンドルや共有ハンドルでは何故かエラー番号を取得できないなど、関数に抜けがあったところが追加されました。
まあcurl_share_strerror()とか一生使う機会がなさそうですが。


## [Square bracket syntax for array destructuring assignment](https://wiki.php.net/rfc/short_list_syntax)

listの短縮形が導入されました。
右辺の[]はarray()の短縮形ですが、左辺で[]を使うとlist()の短縮形になります。

```php
	// 同じ
	list($a, $b, $c) = array(1, 2, 3);
	[$a, $b, $c] = [1, 2, 3];
	
	// 1つの式中ではlistと[]を混ぜて使えない
	[[$a, $b]] = [[1, 2]]; // OK
	list([$a, $b]) = array([1, 2]); // Fatal error: Cannot mix [] and list()

	// listキーと混ぜる
	['c'=>$c, 'a'=>$a] = ['a'=>1, 'b'=>2, 'c'=>3];
```

array()と[]は混ぜて使えますが、list()と[]は同時に使用できません。
α1で導入された[list()キー](http://qiita.com/rana_kualu/items/476385b674d27339f911#allow-specifying-keys-in-list)は一緒に使えるので、下手に混ぜるとカオスになりそうです。


## [Deprecate mb_ereg_replace eval option](https://wiki.php.net/rfc/deprecate_mb_ereg_replace_eval_option)

[mb_ereg_replace](http://php.net/manual/ja/function.mb-ereg-replace.php)のeオプションがE_DEPRECATEDになりました。
むしろ[PCRE](http://php.net/manual/ja/function.preg-replace.php)では5.5で早々と非対応、7.0で削除されたのに、何故こちらが今まで残っていたのかが謎。


## [Deprecate (and remove) Mcrypt](https://wiki.php.net/rfc/mcrypt-viking-funeral)

[mcrypt関数](http://php.net/manual/ja/ref.mcrypt.php)が全てE_DEPRECATEDになりました。
次のバージョンで削除される予定です。
libmcryptは脆弱性を残したまま2007年に放棄されたうえ、mcryptでできることはOpenSSLでよりよくできるので、一刻も早く移行しましょうそうしましょう。


## [Octal Overflow Protection](https://wiki.php.net/rfc/octal.overload-checking)

文字列の8進コード展開において、不正な入力値はE_WARNINGを出すようになりました。
https://bugs.php.net/bug.php?id=71994

```
var_dump("\200" === "\600"); // Warning: Octal escape sequence overflow \600 is greater than \377
                             // 7.0まではtrue
```

ただエラーメッセージは"\377"より大きければエラーって書いてあるんだけど、実際は"\399"までOKで、"\400"以上でエラーが出るようになっていました。
いやまあ"\399"が不正ってのはおいといて。
というかそもそも["\ddd"で8進コードdddの文字を表す](http://php.net/manual/ja/regexp.reference.escape.php)ってのを今初めて知ったよ。

```php
	var_dump("\141"==='a', "\012"==="\n"); // true, true
```


## [Forbid dynamic calls to scope introspection functions](https://wiki.php.net/rfc/forbid_dynamic_scope_introspection)

extract()のような現在のスコープを直接変更する関数の動的呼び出しが禁止されます。

```php
	array_map('extract', [['a' => 42]]); // Warning: Cannot call extract() dynamically
	call_user_func('extract', ['a'=>42]); // OK
	(function($x){extract($x);})(['a'=>42]); // OKだが$a=Undefined
```

どういう条件なのか意味がよくわからなかった。


## [Throw Error in Extensions](https://wiki.php.net/rfc/throw_error_in_extensions)

```php
$iter = new ArrayIterator(new stdClass());
$iter->append(1); // Fatal error: Uncaught Error: Cannot append properties to objects
                  // 7.0β2まではCatchable fatal error
```

エクステンションはこれまで基本的にE_**を出してたけど、対応したところは今後Errorをthrowするようになります。
つうかExceptionなのにErrorって名前のせいでややこしいんじゃ。


## [More precise float value handling](https://wiki.php.net/rfc/precise_float_value)

precision、serialize_precisionに設定値-1が導入されます。
float値をjson_encodeすると値がおかしくなっていたのを、なるだけ正確に計算するようになります。

```php
	ini_set('precision', -1);
	ini_set('serialize_precision', -1);

	$v = 10.0000000000001; // 1e-13
	var_dump($v, json_encode($v), var_export($v, true));
		// 7.1.0α3以降 float(10.0000000000001), string(16) "10.0000000000001", string(16) "10.0000000000001"
		// 7.1.0α2まで float(10), string(2) "10", string(18) "10.000000000000099"
```

元はjson_encodeどころかvar_dumpしただけでおかしいじゃないか。

まあ、この設定でも$v = 10.000000000000001 (1e-15)にするだけでおかしくなるので完璧ではありませんが。
やはり小数はGMPで扱って文字列で受け渡すのが一番だな。


## [Asynchronous Signal Handling](https://wiki.php.net/rfc/async_signals)

[PCNTL](http://php.net/manual/ja/book.pcntl.php)でのプロセス制御を非同期に行うには現状`declare(ticks=1)`とするしかないが、これには無駄に大きなオーバーヘッドがかかる。
そこでpcntl_async_signals()を導入してもっと簡単に非同期できるようにしよう。
とかそういう話みたいなのですが、Windows環境ではそもそもPCNTLが動かないのでどうしようもなかった。


## [Additional Context in pcntl_signal Handler](https://wiki.php.net/rfc/additional-context-in-pcntl-signal-handler)

[pcntl_signal](http://php.net/manual/ja/function.pcntl-signal.php)に第二引数の第二引数$siginfoが追加されました。

```php
	pcntl_signal(SIGUSR1, function ($signo, $siginfo) {
	    var_dump($siginfo);
	});
```

元々UNIXのシグナルハンドラは追加でコンテキスト情報を通知しているのですが、それをPHP側で受け取る方法がありませんでした。
今後は$siginfoで追加情報を受け取れるようになります。

なおWindowsではPCNTL(略


## その他

2016/07/27現在、セッションIDの新たな生成方法についての[RFC](https://wiki.php.net/rfc/session-id-without-hashing)が投票フェーズになっています。
具体的にはsession.sid_bits_per_character/session.sid_lengthが追加、session.hash_function/session.hash_bits_per_character/session.entropy_file/session.entropy_lengthが削除されます。
まだ投票フェーズなのでREJECTされる可能性は十分あるわけですが、なのに[マニュアル](http://php.net/manual/ja/session.configuration.php)には既に「PHP 7.1.0 で導入されました」「PHP 7.1.0 で削除されました」と導入決定済のように書かれている。
なんだこれ。
マニュアルの改訂履歴は見ていないので、誰がいつやったのかは知りません。

なお、β1の時点ではsession.sid_bits_per_character/session.sid_length共に対応していません。


## まとめ

PHP5から7.0と同じかそれ以上の変わりかたになるんじゃないかこれ。