PHP Conference 2014 を聞いてきました
PHP Conference 2014 というイベントに参加してきました。このような大規模なイベントに参加するのは初めてだったのですが、どのセッションもとても面白い話が聞けて、楽しく過ごさせてもらいました。
私はどちらかというと、フレームワークやサービスの話よりも言語処理系そのものに興味があるので、最初はこちらのセッションに参加しました。
PHPコアから読み解くPHP5.5
最初の方のスライドで、PHP 5.5 の新機能の一覧の中に配列リテラルのデリファレンスがあったのですが、これが PHP 5.4 まで出来なかったとは知りませんでした。以下のようなコードを書いて試してみます。
<?php print array(1, 2, 3)[0] . "\n";
たしかに、PHP 5.4 だとシンタックスエラーになってしまいました。
$ php -v PHP 5.4.16 (cli) (built: Sep 30 2014 09:44:39) Copyright (c) 1997-2013 The PHP Group Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies with Zend OPcache v7.0.3, Copyright (c) 1999-2014, by Zend Technologies $ php array_derefence.php PHP Parse error: syntax error, unexpected '[' in /home/y-uti/array_derefence.php on line 2
このコードは、PHP 5.5 ではエラーにならず 1 が出力されます。
$ php -v PHP 5.5.17 (cli) (built: Oct 10 2014 22:18:22) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies with Xdebug v2.2.5, Copyright (c) 2002-2014, by Derick Rethans $ php array_derefence.php 1
これはパーザの問題で、PHP 5.4 では以下のように実装されているところが、
expr_without_variable: ... | T_ARRAY '(' array_pair_list ')' { $$ = $3; }
(https://github.com/php/php-src/blob/php-5.4.33/Zend/zend_language_parser.y#L794)
PHP 5.5 では以下のように変更されていました。
expr_without_variable: ... | combined_scalar_offset { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); }
(https://github.com/php/php-src/blob/PHP-5.5.18/Zend/zend_language_parser.y#L807)
combined_scalar_offset の定義は次のようになっていて、これで、配列リテラルのデリファレンスが受理されます。
combined_scalar_offset: combined_scalar '[' dim_offset ']' { zend_do_begin_variable_parse(TSRMLS_C); fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } | combined_scalar_offset '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } | T_CONSTANT_ENCAPSED_STRING '[' dim_offset ']' { $1.EA = 0; zend_do_begin_variable_parse(TSRMLS_C); fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } combined_scalar: T_ARRAY '(' array_pair_list ')' { $$ = $3; } | '[' array_pair_list ']' { $$ = $2; }
(https://github.com/php/php-src/blob/PHP-5.5.18/Zend/zend_language_parser.y#L827)
似たような話として、PHP 5.3 までは、配列を戻す関数の戻り値を直接デリファレンスできない問題がありました。以下のようなコードです。
<?php function make_array() { return array(1, 2, 3); } print make_array()[0] . "\n";
$ php -v PHP 5.3.29 (cli) (built: Sep 27 2014 21:58:30) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2014 Zend Technologies with Xdebug v2.2.5, Copyright (c) 2002-2014, by Derick Rethans $ php array_retval_dereference.php PHP Parse error: syntax error, unexpected '[' in /home/y-uti/array_retval_dereference.php on line 3
私は、これには本当にイライラしていて、個人的には PHP 5.4 の最大の改善はこれを修正したことだったと思っているのですが、配列リテラルに関してまだ問題が残っていたとは思ってもみませんでした。
phpenv 管理下の PHP に vld を導入する
さて、このセッションでは、PHP 5.5 の新機能のいくつかについて性能比較を含めた紹介がありました。発表資料にはバイトコード命令列が掲載されていましたが、PHP では、vld という PECL 拡張モジュールをインストールすることで、バイトコード命令を出力できます。
ところが、私は anyenv + phpenv + phpbuild で複数のバージョンの PHP を切り替えられるようにしているのですが、この環境では PECL がインストールされません。そのため、拡張モジュールを導入するには、phpize を使ってソースコードからビルドする必要がありました。vld の場合であれば、次の手順で phpenv の環境に導入できました。
まず、ウェブサイトから vld のソースコードをダウンロードして展開します。
$ wget http://pecl.php.net/get/vld-0.12.0.tgz $ tar zxf vld-0.12.0.tgz
phpenv を使って、PHP のバージョンを選択しておきます。
$ phpenv global 5.5.17 phpenv v0.0.4-dev 5.5.17
ソースコードを展開したディレクトリで phpize を実行します。
$ cd vld-0.12.0 $ phpize Configuring for: PHP Api Version: 20121113 Zend Module Api No: 20121212 Zend Extension Api No: 220121212
あとは、普通の make の手順どおりです。なお、通常は make install するときには sudo などを使いますが、phpenv の環境に導入するので、一般ユーザのままで install できます。
$ ./configure ... $ make ... $ make install ...
インストール後、vld.ini を作成します。ディレクトリ階層は phpenv の導入形態によって異なると思いますが、私の環境では以下の場所に作成すればよいようです。
$ cd ~/.anyenv/envs/phpenv/versions/5.5.17/etc/conf.d $ vi vld.ini extension="/home/y-uti/.anyenv/envs/phpenv/versions/5.5.17/lib/php/extensions/no-debug-non-zts-20121212/vld.so"
これで、phpenv 管理下の PHP でも vld を利用できます。ためしに、セッションでも紹介された boolval を使うコードを書いてみました。
<?php print boolval(1.0) . "\n";
実行すると以下のようなバイトコード命令列が表示されます。
$ php -dvld.active=1 boolval.php Finding entry points Branch analysis from position: 0 Return found filename: /home/y-uti/boolval.php function name: (null) number of ops: 9 compiled vars: none line # * op fetch ext return operands --------------------------------------------------------------------------------- 2 0 > EXT_STMT 1 EXT_FCALL_BEGIN 2 SEND_VAL 1 3 DO_FCALL 1 $0 'boolval' 4 EXT_FCALL_END 5 CONCAT ~1 $0, '%0A' 6 PRINT ~2 ~1 7 FREE ~2 3 8 > RETURN 1 branch: # 0; line: 2- 3; sop: 0; eop: 8 path #1: 0, 1
なお、現在公開されている vld 0.12.0 は、PHP 5.5 までの対応のようです。PHP 5.6.1 で phpize して make を試みたところ、コンパイルエラーになってしまいました。