名前空間と並ぶPHP 6の大きな変更点として、「国際化対応」があります。「ん? これまでもmbstringがあったじゃん」と思われるかもしれませんが、mbstringはあくまでもエクステンション。つまり拡張機能であって、PHP本体の機能ではありませんでした。

もちろん、我々マルチバイト文字言語圏の住人にとって、mbstring拡張は欠かせない機能です。しかし、英語圏を中心としたISO-8859-1エンコーディングしか使わない人たちにしてみれば、不要な上に不具合対応も面倒な「鬼っ子」機能でしかありません。

事実、いくつかのLinuxディストリビューションでは、PHPの公式パッケージにmbstring拡張が含まれないなんてこともしばしばでした。しかし、PHP 6からはPHP本体に国際化の機能が実装されるため、マルチバイト言語の基本的な処理に関しては、我々もより安心して利用できるようになりそうです。

さて、このPHP 6の国際化機能は、主に「ICU (International Components for Unicode)」ライブラリを利用して実装されています。ICUは、IBMが提供するUnicodeと国際化処理のためのC/C++、Java向けライブラリで、オープンソースライセンスの下で配布されています。文字エンコーディング変換、日付や通貨の書式変換、ユニコード対応の正規表現などの機能が必要なアプリケーション開発では標準的に利用されているので、既に利用経験のある開発者の方も多いでしょう。

PHP 6では、ソースコードからのビルド時に、あらかじめICUライブラリがインストールされていることが要求されます。組み込まれているICUのバージョン等は、phpinfo()関数の出力結果に表示されますので、一度確認してみるとよいでしょう。

では、PHP 6の具体的な国際化対応を見ていくことにしましょう。まず、php.iniで設定を行います。php.iniの「Unicode settings」セクションを以下のように変更した後、Apacheを再起動して設定を反映しましょう。

;;;;;;;;;;;;;;;;;;;;
; Unicode settings ;
;;;;;;;;;;;;;;;;;;;;

unicode.semantics = on               
unicode.runtime_encoding = utf-8
unicode.script_encoding = utf-8
unicode.output_encoding = utf-8
unicode.from_error_mode = U_INVALID_SUBSTITUTE
unicode.from_error_subst_char = 3f

php.iniのUnicode設定に関する主なディレクティブは、それぞれ以下のような意味を持ちます。

  • 「unicode.semantics」: Unicode機能の有効・無効を切り替えます
  • 「unicode.runtime_encoding」: 関数の引数、文字列連結、比較など、PHPスクリプトの実行時に内部的にバイナリ文字列を変換する際に使用するエンコーディングを指定します
  • 「unicode.script_encoding」: スクリプトの記述に使用するエンコーディング
  • 「unicode.output_encoding」: 出力エンコーディング。mbstring拡張では出力バッファを利用してエンコーディングの変換を行っていましたが、PHP 6ではechoやprintで出力されるデータが、この設定に従って自動的に変換されます

設定が済んだら、簡単なスクリプトを動かしてみます。これまでのPHPでは、国際化対応があくまでもエクステンションのレベルで行われていたため、言語自体のもつコアな関数には、マルチバイト文字について考慮されていないものも多々ありました。例えば、文字列を構成する「文字数」を返す「strlen」は、マルチバイト文字を引数にした場合に、文字数ではなくバイト数を返してしまいます。試しに、PHP 5以前の環境で以下のスクリプトを実行してみましょう(※)。

<?php
echo strlen('こんにちは');
?>

※ スクリプトのエンコーディング、mbstring.internal_encodingは共にUTF-8

「こんにちは」は5文字なのですが、結果としては「15」が返されるはずです。この問題を回避するためには、開発者が意識してmbstring拡張の「mb_strlen」関数や、iconv拡張の「iconv_strlen」関数を使うなどの対応が必要だったのです。

一方PHP 6では、コアな関数も国際化・UNICODEに対応していますので、unicode.semanticsがonならば、strlen関数も正しく「こんにちは」を「5文字」だと認識してくれます。