unichr()

ふとした思いつきで Python の unichr() を PHP で書いてみました。
UCS-2 のコードポイントに対応した UTF-8 の文字(列)を返す関数です。
オリジナルは Unicode 文字列型のオブジェクトを返すのですが、バージョン 6 未満の PHP にはそんなものは無いので UTF-8 で。

function unichr($cp)
{
    if ($cp < 0 || $cp > 0xFFFF) {
        return false;
    }
    if ($cp < 0x80) {
        return chr($cp);
    }
    if ($cp < 0x800) {
        return pack('CC', 0xC0 | $cp >> 6, 0x80 | $cp & 0x3F);
    }
    return pack('CCC', 0xE0 | $cp >> 12, 0x80 | $cp >> 6 & 0x3F, 0x80 | $cp & 0x3F);
}

で、さらにちょっと弄って、サロゲートペアを含む UTF-16 の範囲にまで対応させてみます。

function unichr2($cp)
{
    if ($cp < 0 || ($cp > 0xD7FF && $cp < 0xE000) || $cp > 0x10FFFF) {
        return false;
    }
    if ($cp < 0x80) {
        return chr($cp);
    }
    if ($cp < 0x800) {
        return pack('CC', 0xC0 | $cp >> 6 & 0x1F, 0x80 | 0x3F & $cp);
    }
    if ($cp < 0x10000) {
        return pack('CCC', 0xE0 | $cp >> 12, 0x80 | $cp >> 6 & 0x3F, 0x80 | $cp & 0x3F);
    }
    return pack('CCCC', 0xF0 | $cp >> 18, 0x80 | $cp >> 12 & 0x3F, 0x80 | $cp >> 6 & 0x3F, 0x80 | $cp & 0x3F);
}

ここまで書いて、PEARI18N_UnicodeString というパッケージがあったことを思い出し、中を見てみたら...
案の定 unicodeCharToUtf8() という、そのものズバリのメソッドがありましたよ。orz
I18N_UnicodeString:: unicodeCharToUtf8() は UCS-4 の領域をフルサポートしているようです。
まあ車輪の再発明であろう事は覚悟してましたが...
悔し紛れにベンチマークをしてみる。

require_once 'I18N/UnicodeString.php';
$t0 = microtime(true);
for ($i = 0; $i < 10000; $i++) I18N_UnicodeString::unicodeCharToUtf8(0x3000);
$t1 = microtime(true);
for ($i = 0; $i < 10000; $i++) unichr(0x3000);
$t2 = microtime(true);
for ($i = 0; $i < 10000; $i++) unichr2(0x3000);
$t3 = microtime(true);
printf("%0.6f / %0.6f / %0.6f?n", $t1 - $t0, $t2 - $t1, $t3 - $t2);

結果:

0.295587 / 0.106597 / 0.118184

何回か試したところ、拙作の unichr() のほうが 2〜3 倍ほど速かったです。
コードの中身よりスタティックメソッド vs 関数の呼び出し速度の違いが大部分を占める訳ですが。
unicodeCharToUtf8() をコピペして関数として呼び出した場合の結果はこの通り。

0.267475 / 0.106666 / 0.123373 / 0.144367

せいぜい 20〜40% ほどしか差はなくなりましたが、文字列を結合するより一発で書き出す方が速いのは確かなようです。