PHP: 2007年7月アーカイブ

PHP 6.0 開発版を試す

| | コメント(6)

PHP Snapshots の PHP 6.0 開発版を試してみました。

Apache の設定とか

PHP 5.x の時と同じ手順で動きました。今回使った設定

    LoadFile "C:\PHP\6.0.0-dev-200707112230\php6ts.dll"
    LoadModule php6_module "C:\PHP\6.0.0-dev-200707112230\php6apache2_2_filter.dll"
    AddInputFilter PHP php
    AddOutputFilter PHP php
    PHPINIDir "C:\PHP\6.0.0-dev-200707112230"

php.ini

register_globals や magic_quotes、safe_mode 辺りがばっさり削られてました。その他、Unicode のディレクティブが追加されています。

Unicode への対応が強化

まず設定ディレクティブから

ドキュメントが(見付から)ない部分は憶測で書いています。

unicode.semantics
unicode 機能が使用可能かどうか。設定できる箇所は、PHP_INI_PERDIR なので php.ini, .htaccess または httpd.conf です。(php.ini-recommemded で off ってのはどうかしら?どうかしら?)
unicode.runtime_encoding
実行エンジンが内部で取り扱う文字符号化方式。詳しくはこちらを参照
unicode.script_encoding
PHP スクリプト ファイルの文字符号化方式。御法度だった Shift_JIS での記述も可能に。
unicode.output_encoding
出力時の文字符号化方式。mbstring 関数の mbstring.http_output に相当する機能?
unicode.from_error_mode
不正な文字をどうするか。U_INVALID_SUBSTITUTE は unicode.from_error_subst_char で指定したコード ポイントを持つ文字に置き換え。
unicode.from_error_subst_char
不from_error_mode = U_INVALID_SUBSTITUTE 時に置き換える文字。Unicode のコード ポイントで指定?

指定できるエンコーディングは、Unicode 関数が利用しているライブラリ ICU がサポートしているものをそのまま使うようです。

使ってみる

普通に使う

// 文字列リテラルは Unicode 扱い
$string = "文字列リテラルは Unicode 扱い";
var_dump($string);
# unicode(19) "文字列リテラルは Unicode 扱い"

// \u により、Unicode 文字をコード ポイント指定で埋め込める
$string = "\u307a\u3061\u3071\u30fc";
var_dump($string);
# unicode(4) "ぺちぱー"

// カウントばっちり
var_dump(strlen($string));
# int(19)

// 切り取りもばっちり
var_dump(substr($string, 9, 7));
# unicode(7) "Unicode"
バイナリから Unicode へのキャスト

string 型から unicode 型へは unicode.runtime_encoding の文字符号化方式に基づいて変換しているようです。

例えば、unicode.runtime_encoding = Shift_JIS、その他を UTF-8 な環境化では…

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

unicode.semantics = on
unicode.runtime_encoding = Shift_JIS
unicode.script_encoding = UTF-8
unicode.output_encoding = UTF-8
unicode.from_error_mode = U_INVALID_SUBSTITUTE
unicode.from_error_subst_char = 3f
# Shift_JIS で符号化された文字列「あいう」
$binary = pack('C*', 0x82, 0xa0, 0x82, 0xa2, 0x82, 0xa4);

// バイナリを扱う関数の戻り値は string のままらしい
var_dump($binary);
# string(6) "??????"

// unicode 型へキャスト。
$unicode = (unicode)$binary;
var_dump($unicode);
# unicode(3) "あいう"
そんな訳で

PHP 6.0 で文字列を取り扱う時は、従来の string 型と Unicode 専用の unicode 型で分けて考えるようになりました。

正規表現関数とパターン修飾子 u

正規表現関数 にて、UTF-8 での処理を有効にするパターン修飾子 u を使うと、Unicode のカテゴリが使用できるというお話。

文章的に意味がなさそうな文字列を判別しちゃう(サイコロを振るよりはマシ程度)

$strings = array(
        '0123456789',
        'Latin',
        'ひらがな',
        'カタカナ',
        '漢字',
        '한글',
        'αβγ',
        '+-*/=<>', 
        '「」()『』',
        pack('C*', 0xe2, 0x80, 0x8b), // U+200B (Zero Width Space) 
    );

foreach ($strings as $string)
{
    $hasLetter = preg_match('/\\p{L}/u', $string);
    printf('"%s" has letter? %s' . "\r\n", $string, $hasLetter ? 'Yes' : 'No');
}



// "0123456789" has letter? No
// "Latin" has letter? Yes
// "ひらがな" has letter? Yes
// "カタカナ" has letter? Yes
// "漢字" has letter? Yes
// "한글" has letter? Yes
// "αβγ" has letter? Yes
// "+-*/=<>" has letter? No
// "「」()『』" has letter? No
// "​" has letter? No
 

絵文字の変換

// U+E000 ~ U+E8FF までのブロックは Private Use Area

function pictographToText($capture)
{
    $table = array(
            pack('C*', 0xee, 0x98, 0xbe) => '晴れ', // U+E63E (i-mode 基本絵文字 "晴れ")
            pack('C*', 0xee, 0x98, 0xbf) => '曇り', // U+E63F (i-mode 基本絵文字 "曇り")
            pack('C*', 0xee, 0x99, 0x80) => '雨',   // U+E640 (i-mode 基本絵文字 "雨")
        );

    return isset($table[$capture[0]]) ? $table[$capture[0]] : '?';
}


$string = '今日の天気は '
    . pack('C*', 0xee, 0x98, 0xbe)
    . ' です。'
    . '明日の天気は '
    . pack('C*', 0xee, 0x99, 0x80)
    . ' かも?';

echo preg_replace_callback('/\\p{Co}/u', 'pictographToText', $string);


// 今日の天気は 晴れ です。明日の天気は 雨 かも?

参考

5.2.0 で仕様が変わっていたインターフェイス

5.2.0 でインターフェイスに対して手が加えられたよう。だけど、この仕様変更についてはどうかと疑問を感じました。

自分はインターフェイスについてこう考えている

疑問点を述べる前に、自分が持つインターフェイスについての考え方を述べておきます。インターフェイスとは、オブジェクトに対して所属するクラスに関係なく公開された振る舞いを定義する方法だと考えています。例えば…


// 感情表現するためのインターフェイスを定義

/**
 * ツンツンするメソッドを定義します。
 */
interface ITuntun
{
    public function tun();
}

/**
 * デレデレするメソッドを定義します。
 */
interface IDeredere
{
    public function dere();
}


/**
 * モチモチするメソッドを定義します。
 *
 */
interface IMochimochi
{
    public function mochi();
}
// 感情表現できるクラスを定義

/**
 * お嬢様を表します。
 */
class Ojyohsama implements ITuntun, IDeredere
{
    /**
     * ツンツンします。
     */
    public function tun()
    {
        echo 'べ、べつにあんたのためじゃないんだからね!';
    }
    
    /**
     * デレデレします。
     */
    public function dere()
    {
        echo '頼れるのはあんただけなんだから…';
    }
}


/**
 * ひこにゃんを表します。
 */
class Hikonyan implements IDeredere, IMochimochi
{
    /**
     * デレデレします。
     */
    public function dere()
    {
        echo '一緒に写真とるにゃんー1枚50元払えニャン';
    }
    
    /**
     * モチモチします。
     */
    public function mochi()
    {
        echo 'エレベータにはさまったニャン!';
    }
    
}


// んでもって実行。

// お嬢様もひこにゃんも組み込みクラスも一緒くたにして…
$objects = array(
        new Ojyohsama(),
        new Hikonyan(),
        new stdclass(),
        new DOMDocument(),
    );

// オブジェクトのうち、IDeredere を実装したものだけデレデレさせる。
foreach ($objects as $object)
{
    if ($object instanceof IDeredere)
    {
        $object->dere();
    }
}


インスタンスの初期化をインターフェイスで縛ることに意味があるのか?

付録 B. PHP 5.1.x から PHP 5.2.x への移行その他の機能向上 より。

インターフェイスのコンストラクタで、 実装クラスのコンストラクタのシグネチャを強制できるようになりました。

PHP 5.2.0 以降で、インターフェイスにコンストラクタを定義できるようになりました。 しかし、インターフェイスでコンストラクタを宣言した場合は、 そのインターフェイスを実装するクラスは インターフェイスのコンストラクタと同じシグネチャのコンストラクタを持つ必要があります。 ここでいう「シグネチャ」とは、パラメータや返り値の定義のことです。 また、型ヒントや 参照渡し/値渡し の区別なども含まれます。

コンストラクタがはたしてインターフェイスに含まれるべきかを焦点にすると、含まれるべきではないと思います。コンストラクタはあくまでクラスのインスタンスを初期化する役割であり、またその手段のシンタックス シュガーであり、オブジェクトの振る舞いの定義とは違います。振る舞いを示すメソッドと表現が似ているだけで別物と考えるべきです。

また、インターフェイスは横断的に implements できるので、当然コンストラクタの衝突が考えられます。多重継承の問題が再蜂起しそう…。

そもそもの要求であるコンストラクタのシグネチャを保証させたいのなら、抽象クラスを使うべきだし、オブジェクトの作成方法を統一するならデザパタの Factory Method パターンがより分かりやすく思えます。

インターフェイスはインスタンスに関わる定義だけじゃない?

付録 B. PHP 5.1.x から PHP 5.2.x への移行その他の機能向上 より。

abstract static なクラス関数が削除されました。

ちょっとした手違いで、PHP 5.0.x および 5.1.x では abstract static な関数をクラス内で定義できてしまっていました。PHP 5.2.x では、 これはインターフェイス内でのみ定義できるようになりました。

static なメンバの定義について、これもインターフェイスがオブジェクトの振る舞いを定義するものならお役違いだと思います。static なメンバには当然オブジェクトがないのでインターフェイスを利用する場面でもありません。

[ここにオブジェクトのクラスに存在する static メソッドを呼び出すコードを書く]

無理して使うほどでもないし、abstract static の存在からして謎。実装を再定義する必要があるものを static にする設計がおかしい気がします。

追記

こうして考えると PHP のインターフェイスはテンプレートとしての役割なのかなぁ…。もう少し考えてみます。

このアーカイブについて

このページには、2007年7月以降に書かれたブログ記事のうちPHPカテゴリに属しているものが含まれています。

前のアーカイブはPHP: 2007年6月です。

次のアーカイブはPHP: 2007年8月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Powered by Movable Type 4.12