PHP5.5 Alpha1リリース! 新機能を俯瞰する
こんにちは、久保田です。
PHP5.5 Alpha1が11/15日付けでリリースされました。この記事では以下のような新機能や変更を紹介します。
・ジェネレータとコルーチンの追加
・finallyキーワードの追加
・配列や文字列のデリファレンスのサポート
・foreachの中でのlist 表現
・PCRE正規表現での/e修飾子が非推奨化
・NEWS翻訳
ジェネレータとコルーチンの追加
PHP5.5での一番大きな新機能は、ジェネレータとコルーチンの追加です。文法にyield構文が追加されました。
まずは、ジェネレータを説明します。例えば以下の様なコードが動きます。
<?php
function hoge()
{
yield "hoge";
yield "fuga";
yield "piyo";
}
foreach (hoge() as $str) {
var_dump($str);
}
これをPHP5.5で実行すると以下のように出力されます。
string(4) "hoge"
string(4) "fuga"
string(4) "piyo"
ジェネレータでは、yield構文を使ってforeachなどで利用できる値の列を生成することができます。
このコード例を見ただけだと、関数で配列を返したりイテレータを使うのと何が違うのかわからないと思います。PHP5.5で実装されたジェネレータの一番の特徴は、ジェネレータ内で一度値を生成すると計算が途中で止まって呼び出し元へ制御が復帰し、再びジェネレータ内に制御が戻ると以前の計算の位置から処理が再開されるということです。
以下のような例を実行します。
<?php
function hoge()
{
echo "generating a\n";
yield 'a';
echo "generating b\n";
yield 'b';
echo "generating c\n";
yield 'c';
}
function fuga()
{
$ret = [];
echo "add a\n";
$ret[] = 'a';
echo "add b\n";
$ret[] = 'b';
echo "add c\n";
$ret[] = 'c';
return $ret;
}
foreach (hoge() as $char) {
echo $char . "\n";
}
echo "\n";
foreach (fuga() as $char) {
echo $char . "\n";
}
実行すると以下のように出力されます。配列で返すやり方とは違って、ジェネレータ内のyieldで値を返すごとにforeachのループに制御が戻ることがわかります。
generating a
a
generating b
b
generating c
c
add a
add b
add c
a
b
c
ジェネレータを利用すると、イテレータで実装するのとは違って状態をオブジェクトのプロパティなどで管理する必要がなくなり、コード量が劇的に減ります。また、配列を直接返す形式よりもメモリ使用量を抑えることもできます 。
無限のフィボナッチ数列も簡単に生成できます。
<?php
function fib()
{
yield $prev = 1;
yield $n = 1;
for (;;) {
list($prev, $n) = [$n, $prev + $n];
yield $n;
}
}
foreach (fib() as $n) {
if ($n > 100) {
break;
}
echo $n . "\n";
}
0から100までの間のフィボナッチ数列が生成できました。
1
1
2
3
5
8
13
21
34
55
89
次はコルーチンを説明します。コルーチンもジェネレータと同様にyield構文を利用します。
<?php
function hoge()
{
for (;;) {
var_dump(yield);
}
}
$hoge = hoge();
$hoge->send("fuga");
$hoge->send("piyo");
$hoge->send("foo");
これを実行すると出力が以下です。
string(4) "fuga"
string(4) "piyo"
string(6) "foobar"
コルーチンでは、計算の途中で呼び出し元から引数を受け取る事ができます。ジェネレータが値を一度生成すると計算がその場で止まるのと同様に、コルーチンの中では呼び出し元から引数を受け取るまで計算が止まります。ジェネレータと違うところは、ジェネレータが値の列を返し続けるものであるのに対して、コルーチンは値の列を取り続けるところです。
参考:
・PHP5.5新機能「ジェネレータ」初心者入門
・PHP: rfc:generators [PHP Wiki]
finallyキーワードの追加
try構文のとともに利用するfinallyキーワードがサポートされるようになりました。finally構文を置くと、try-catchブロックを抜ける際に確実にfinallyブロックの中が実行されます。例えばファイルハンドルやリソースの後片付けのコードを正しく書けるようになります。
<?php
$db = mysqli_connect();
try {
call_some_function($db);
} catch (Exception $e) {
throw $e;
} finally {
mysqli_close($db);
}
参考:
・Request for Comments: Supports finally keywordを和訳してみた
配列や文字列でのデリファレンスのサポート
PHP5.4では関数の戻り値からのデリファレンスがサポートされましたがリテラルからはできませんでした。
<?php
function hoge() {
return ["hoge", "fuga", "foo"];
}
var_dump(hoge()[1]); // PHP5.4からこれが大丈夫になった
["hoge", "fuga", "foo"][1]; // PHP5.4ではパースエラー
PHP5.5では配列や文字列のリテラルから直接デリファレンスできるようになりました。
<?php
var_dump(["hoge", "fuga", "foo"][2]); // => "foo"
var_dump("hoge"[2]); // => "g"
foreachの中でのlist表現
foreach構文で要素を受け取る部分でのlist表現がサポートされました。
<?php
list($a, $b) = [1, 2]; // PHP5.5以前のlist表現の使い方
$arr = [
["hoge", "fuga"],
["foo", "bar"]
];
foreach ($arr as list($left, $right)) { // PHP5.5でサポートされる書き方
echo $left . ":" . $right;
}
PCRE正規表現での/e修飾子の非推奨化
セキュリティ脆弱性を作ってしまいがちであるPCRE正規表現での/e修飾子が非推奨となりました。preg_replace関数で文字列を置換する際の加工のためにPHPの関数を用いたい場合は、pref_replace_callback関数を利用しましょう。
参考:
・http://php.net/reference.pcre.pattern.modifiers
NEWS翻訳
最後に、PHP5.5 Alpha1のNEWSファイルの簡単な翻訳です。細かな変更はこれを確認してみてください。
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
13 Nov 2012, PHP 5.5.0 Alpha 1
- 一般的な改善:
General improvements:
. ジェネレータの追加。
Added support for generators. (Nikita Popov)
. パスワードハッシュ化のための単純化されたAPIの追加
Add simplified password hashing API
(https://wiki.php.net/rfc/password_hash). (Anthony Ferrara)
. ジェネレータとコルーチンの追加。
Add generators and coroutines (https://wiki.php.net/rfc/generators).
(Nikita Popov)
. foreach文の中でのlist表現のサポート(https://wiki.php.net/rfc/foreachlist)
Support list in foreach (https://wiki.php.net/rfc/foreachlist). (Laruence)
. 'finally'の実装(https://wiki.php.net/rfc/finally) (Laruence)
Implemented 'finally' keyword (https://wiki.php.net/rfc/finally). (Laruence)
. Windows XPとWindows 2003のサポート廃止 (Pierre)
Drop Windows XP and 2003 support. (Pierre)
. reset中のset_exception_handlerの改善 (Laruence)
Improve set_exception_handler while doing reset.(Laruence)
. 配列や文字列リテラルのデリファレンスのサポート
Support constant array/string dereferencing. (Laruence)
. 関数呼び出しの結果をempty()に渡せるようにした
Add support for using empty() on the result of function calls and
other expressions (https://wiki.php.net/rfc/empty_isset_exprs).
(Nikita Popov)
. php_logo_guid(), php_egg_logo_guid(), php_real_logo_guid(), zend_logo_guid()関数の削除
Remove php_logo_guid(), php_egg_logo_guid(), php_real_logo_guid(),
zend_logo_guid(). (Adnrew Faulds)
- カレンダー:
Calendar:
. #54254バグの修正(Adar(訳注: ヘブライ暦の12番目の月)のみが残っている時、cal_from_jdがmonth = 6を返す)
Fixed bug #54254 (cal_from_jd returns month = 6 when there is only one Adar)
(Stas, Eitan Mosenkis).
- Core:
. boolval()関数の追加。
Added boolval(). (Jille Timmermans).
. pack/unpack関数に"Z"オプションを追加。
Added "Z" option to pack/unpack. (Gustavo)
. 機能要望#60738のの実装('set_error_handler'へnullを設定することを許可)
Implemented FR #60738 (Allow 'set_error_handler' to handle NULL).
(Laruence, Nikita Popov)
. assert関数にカスタムメッセージを設定するための第二オプション引数を追加。
Added optional second argument for assert() to specify custom message. Patch
by Lonny Kapelushnik (lonny@lonnylot.com). (Lars)
. バグ#18556の修正(エンジンがクラス名を扱う時に設定されたロケールのルールを使うバグ) (訳注: ロケールによっては宣言したクラス名が正しく認識されないバグ)
Fixed bug #18556 (Engine uses locale rules to handle class names). (Stas)
. バグ#61681の修正(不恰好な文法) (訳注: 文字列内の変数表現の中で@を使うと、関数呼び出しができてしまうバグ)
Fixed bug #61681 (Malformed grammar). (Nikita Popov, Etienne, Laruence).
. バグ#61038の修正(unpack("a5", "str\0\0") が期待通りに動かない)
Fixed bug #61038 (unpack("a5", "str\0\0") does not work as expected).
(srgoogleguy, Gustavo)
. set_error_handler関数やset_exception_handler関数にNULLを渡した時に以前のハンドラを返す
Return previous handler when passing NULL to set_error_handler and
set_exception_handler. (Nikita Popov)
- cURL:
. オプションのサポート:
Added support for CURLOPT_FTP_RESPONSE_TIMEOUT, CURLOPT_APPEND,
CURLOPT_DIRLISTONLY, CURLOPT_NEW_DIRECTORY_PERMS, CURLOPT_NEW_FILE_PERMS,
CURLOPT_NETRC_FILE, CURLOPT_PREQUOTE, CURLOPT_KRBLEVEL, CURLOPT_MAXFILESIZE,
CURLOPT_FTP_ACCOUNT, CURLOPT_COOKIELIST, CURLOPT_IGNORE_CONTENT_LENGTH,
CURLOPT_CONNECT_ONLY, CURLOPT_LOCALPORT, CURLOPT_LOCALPORTRANGE,
CURLOPT_FTP_ALTERNATIVE_TO_USER, CURLOPT_SSL_SESSIONID_CACHE,
CURLOPT_FTP_SSL_CCC, CURLOPT_HTTP_CONTENT_DECODING,
CURLOPT_HTTP_TRANSFER_DECODING, CURLOPT_PROXY_TRANSFER_MODE,
CURLOPT_ADDRESS_SCOPE, CURLOPT_CRLFILE, CURLOPT_ISSUERCERT,
CURLOPT_USERNAME, CURLOPT_PASSWORD, CURLOPT_PROXYUSERNAME,
CURLOPT_PROXYPASSWORD, CURLOPT_NOPROXY, CURLOPT_SOCKS5_GSSAPI_NEC,
CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOPT_TFTP_BLKSIZE,
CURLOPT_SSH_KNOWNHOSTS, CURLOPT_FTP_USE_PRET, CURLOPT_MAIL_FROM,
CURLOPT_MAIL_RCPT, CURLOPT_RTSP_CLIENT_CSEQ, CURLOPT_RTSP_SERVER_CSEQ,
CURLOPT_RTSP_SESSION_ID, CURLOPT_RTSP_STREAM_URI, CURLOPT_RTSP_TRANSPORT,
CURLOPT_RTSP_REQUEST, CURLOPT_RESOLVE, CURLOPT_ACCEPT_ENCODING,
CURLOPT_TRANSFER_ENCODING, CURLOPT_DNS_SERVERS and CURLOPT_USE_SSL.
(Pierrick)
. バグ#55635の修正 (CURLOPT_BINARYTRANSFERはこれからは利用されない。
定数は後方互換性のため残されるが、これはなにもしない。). (Pierrick)
Fixed bug #55635 (CURLOPT_BINARYTRANSFER no longer used. The constant
still exists for backward compatibility but is doing nothing). (Pierrick)
. #54995バグを修正(CURLINFO_RESPONSE_CODEへのサポートが無い)
Fixed bug #54995 (Missing CURLINFO_RESPONSE_CODE support). (Pierrick)
- Datetime
. バグ#61642の修正(modify("+5 weekdays")が月曜を返す)
Fixed bug #61642 (modify("+5 weekdays") returns Sunday).
(Dmitri Iouchtchenko)
- Hash
. hash_pbkdf2()関数でPBKDF2のサポートを追加
Added support for PBKDF2 via hash_pbkdf2(). (Anthony Ferrara)
- Intl
. intlエクステンションがICU4.0以上を要求するようになった。
The intl extension now requires ICU 4.0+.
. intl.error_levelとともにグローバルなエラーがセットされた時の挙動を
コントロールするためのintl.use_exceptions INIディレクティブの追加。
Added intl.use_exceptions INI directive, which controls what happens when
global errors are set together with intl.error_level. (Gustavo)
. MessageFormatter::format()とそれに関連する関数で、ICU4.8