PHP7.1.0の新機能 / PHP7.1β1の新機能 / PHP7.1α1の新機能 / PHP7.0.0α1 / PHP5.6
PHP7.1はどういうわけか新機能をえらい盛り盛りしてきています。
前PHP7.1の新機能というのを書きましたが、その記事はα1時点のものでした。
α2、α3、β1でさらに色々追加されていたので見てみます。
Replace "Missing argument" warning with "Too few arguments" exception
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
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の再定義がついに禁止されました。
α2以降Errorが発生します。
他に関数の引数やextract、globalといった、これまで存在していた抜け道も悉く潰されました。
さらにオブジェクトの外で$this
を使った場合、これまではただのUndefined variableのE_NOTICEでしたが、α2以降はErrorが発生します。
今後$thisはオブジェクト内でしか使用できません。
Iterable
型宣言iterableが追加されました。
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インターフェイスが存在するのに何故新しくiterableなんてものを作ったかというと、配列はTraversableではないからです。
iterableと書くことで、配列を含めたあらゆる反復可能オブジェクトを受け取ることが可能になります。
また、それに伴い関数is_iterable()が追加されました。
文字どおりiterableか否かを判定する関数です。
Nullable Types
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
コールバック関数からClosureを作成できる。
$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()
cURLには通常のcURLハンドル、cURLマルチハンドル、cURL共有ハンドルがありました。
通常ハンドルではcurl_errno()でエラー番号を取得できるのにマルチハンドルや共有ハンドルでは何故かエラー番号を取得できないなど、関数に抜けがあったところが追加されました。
まあcurl_share_strerror()とか一生使う機会がなさそうですが。
Square bracket syntax for array destructuring assignment
listの短縮形が導入されました。
右辺の[]はarray()の短縮形ですが、左辺で[]を使うとlist()の短縮形になります。
// 同じ
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()キーは一緒に使えるので、下手に混ぜるとカオスになりそうです。
Deprecate mb_ereg_replace eval option
mb_ereg_replaceのeオプションがE_DEPRECATEDになりました。
むしろPCREでは5.5で早々と非対応、7.0で削除されたのに、何故こちらが今まで残っていたのかが謎。
Deprecate (and remove) Mcrypt
mcrypt関数が全てE_DEPRECATEDになりました。
次のバージョンで削除される予定です。
libmcryptは脆弱性を残したまま2007年に放棄されたうえ、mcryptでできることはOpenSSLでよりよくできるので、一刻も早く移行しましょうそうしましょう。
Octal Overflow Protection
文字列の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の文字を表すってのを今初めて知ったよ。
var_dump("\141"==='a', "\012"==="\n"); // true, true
Forbid dynamic calls to scope introspection functions
extract()のような現在のスコープを直接変更する関数の動的呼び出しが禁止されます。
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
$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
precision、serialize_precisionに設定値-1が導入されます。
float値をjson_encodeすると値がおかしくなっていたのを、なるだけ正確に計算するようになります。
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
PCNTLでのプロセス制御を非同期に行うには現状declare(ticks=1)
とするしかないが、これには無駄に大きなオーバーヘッドがかかる。
そこでpcntl_async_signals()を導入してもっと簡単に非同期できるようにしよう。
とかそういう話みたいなのですが、Windows環境ではそもそもPCNTLが動かないのでどうしようもなかった。
Additional Context in pcntl_signal Handler
pcntl_signalに第二引数の第二引数$siginfoが追加されました。
pcntl_signal(SIGUSR1, function ($signo, $siginfo) {
var_dump($siginfo);
});
元々UNIXのシグナルハンドラは追加でコンテキスト情報を通知しているのですが、それをPHP側で受け取る方法がありませんでした。
今後は$siginfoで追加情報を受け取れるようになります。
なおWindowsではPCNTL(略
その他
2016/07/27現在、セッションIDの新たな生成方法についてのRFCが投票フェーズになっています。
具体的にはsession.sid_bits_per_character/session.sid_lengthが追加、session.hash_function/session.hash_bits_per_character/session.entropy_file/session.entropy_lengthが削除されます。
まだ投票フェーズなのでREJECTされる可能性は十分あるわけですが、なのにマニュアルには既に「PHP 7.1.0 で導入されました」「PHP 7.1.0 で削除されました」と導入決定済のように書かれている。
なんだこれ。
マニュアルの改訂履歴は見ていないので、誰がいつやったのかは知りません。
なお、β1の時点ではsession.sid_bits_per_character/session.sid_length共に対応していません。
まとめ
PHP5から7.0と同じかそれ以上の変わりかたになるんじゃないかこれ。