2009/12/15

PHPでEnum (C言語風の連番)

PHPでC言語のEnum型のように、定数値を列挙したくなることがあります。

例えばデータベースに下のようなテーブルを定義したときに、
0が犬、1が猫、2がロバを表していることを(C言語のenumのように)簡潔に表現できる型が欲しくなりますよね。

テーブル:my_friends
id
(数値)
name
(文字列)
type
(数値)
1ポチ0(犬)
2猫太郎1(猫)
3ルシオ2(ロバ)





PHP5.6以降の場合

PHP5.6以降では、arrayにconstを指定できるようになったので、
enumセットをconstなarrayとして定義すると使い勝手が良いです。
(const指定した値は、定数なので$を付けずに使います。)

参考: PHPマニュアル PHP 5.5.xからPHP 5.6.x への移行 http://php.net/manual/ja/migration56.new-features.php

Enum定義サンプル:
<?php
//------------------------------------------------------
// Enum値の定義
//
//   constなarrayを作るだけです
//
const FiendType = array(
    'Dog' => 1,
    'Cat'=> 2,
    'Asinus' => 3,
    'Human' => 10
);


//------------------------------------------------------
// Enum値を使う
//

$type = FriendType['Cat']; // typeに猫を設定します

// switch文でtype別の発言をprintしてみます
switch ($type) {
    case FriendType['Dog']:
        print "ワン\n";
        break;

    case FriendType['Cat']:
        print "ニャー\n";
        break;

    case FriendType['Asinus']:
        print "グーヒー、グーヒー\n";
        break;
}

?>
※ 配列要素の参照方法が間違っていたので修正しました。






PHP5.5以前の場合

5.5より前のバージョンのPHPではconstなarrayは定義できないようなので、
arrayの値を変更できないように保護するクラスを作ってみました。

<?php

//
// PHP(5.5)でEnumを使うためのクラス
//
class Enum
{
    //
    // Enumオブジェクトの生成
    //
    private static $enums = array();
    public static function __callStatic($name, $arguments)
    {
        if (is_array($arguments[0])) {
            // 重複チェック
            if (isset(self::$enums[$name])) {
                trigger_error(print "{$name} is exists..", E_USER_ERROR);
            }
            self::$enums[$name] = new Enum($arguments[0]);
        } else {
            if (!isset(self::$enums[$name])) {
                trigger_error("Enum {$name} not found...", E_USER_ERROR);
            }
            return self::$enums[$name];
        }
    }

    //
    // Enumオブジェクトのメソッド
    //
    protected $values = array(); // Enum要素

    // arrayからEnumオブジェクトを生成
    protected function __construct(array $params)
    {
        // Enum値をプロパティへ
        foreach ($params as $key => $p) {
            if (!is_int($key)) {
                trigger_error('Key must be an int.', E_USER_ERROR);
            }
            $this->values[$p] = $key;
        }
    }

    // Enum要素の取得
    public function __get($name)
    {
        if (!isset($this->values[$name])) {
            // 存在しない要素
            trigger_error("[{$name}] isn't enum element", E_USER_ERROR);
        }
        return $this->values[$name];
    }

    // 代入
    public function __set($name, $value)
    {
        trigger_error("Enum can't set.", E_USER_ERROR);
    }
}
?>


実際に連番を定義する時には、下のように使います。
<?php
//
// 連番の定義
//
//   Enum::'連番の名前'()に対して、arrayを渡すだけです。
//
Enum::FriendType(
    array(
        'Dog',  // 犬
        'Cat',  // 猫
        'Asinus', // ロバ
        10 => 'Human' , //いつか人間のFriendができた時のために10番をHumanにしておく、なんてこともできます
    )
);

?>

Enum::のあとにEnumセットの名前を書いて()の中にEnum要素の名前を配列として渡すだけです。
配列のキーがそのまま各要素の値になっているので、上のHUMANのようにキーを指定すれば、
値を指定した要素を作ることもできます。



上で定義した連番を使う場合は、下のようになります。
<?php

$type = Enum::FriendType()->Cat; // typeに猫を設定します

// switch文でtype別の発言をprintしてみます
switch ($type) {
    case Enum::FriendType()->Dog:
        print "ワン\n";
        break;

    case Enum::FriendType()->Cat:
        print "ニャー\n";
        break;

    case Enum::FriendType()->Asinus:
        print "グーヒー、グーヒー\n";
        break;
}

?>
ここでも、Enum::のあとにEnumセットの名前と()を書き、->で各要素にアクセスします。




もっとオブジェクト指向なJava風Enum(Enamlatableなオブジェクト)を定義したいって時は、PHPでJava風のEnum(なごりんぐ)へ。

2 件のコメント:

  1. このサイト間違いだらけだな(笑)

    返信削除
  2. And lastly, these games could be one thing like a baby’s first steps in the betting world. The stakes are lower, and there's be} more room for errors and mishaps. One of the most popular and secure online sports activities betting sites is Betway. They supply one of the best sporting activity and extensive range|a variety} of betting choices in significant leagues and competitions. The 먹튀검증사이트 advertised bonus amount- once you have located a trustworthy web site, you should to} think about the bonus amount being supplied.

    返信削除