phpで無理やりEnum
タイトルのとおり。
phpでもjavaのEnumっぽいの使いたい、何とかできないかしら…。
と思っていろいろ考えてみました。
目標
<?php ItemType::$NORMAL; //アイテムタイプ : 通常 ItemType::$SPECIAL; //アイテムタイプ : 特別 ItemType::$LIMITED; //アイテムタイプ : 限定品 foreach(ItemType::values() as $itemType){ echo "コード値 : {$itemType->getCode()} 表記名 : {$itemType->getDescription()}\n"; }
こんな雰囲気で使いたい。
(タイプにどんな属性を与えられるかは自由に決められる。)
という訳で書いてみたのが以下のコード
Enum基底クラス
<?php class Enum { /** 項目を記録しとくプロパティ */ protected static $enums = array(); /** $enumsに項目を追加するメソッド */ protected static function add(){ // 追加される項目げっと (可変長引数) $addingEnums = func_get_args(); // このメソッドが呼び出されたクラスの名前をげっと $calledClass = get_called_class(); // Enumを継承したクラスごとに項目データを保存 self::$enums[$calledClass] = $addingEnums; } /** このメソッドを呼び出したクラスの項目として設定されているものを取得 */ public static function values(){ $calledClass = get_called_class(); return self::$enums[$calledClass]; } }
ItemTypeクラス
<?php class Item extends Enum { /** 商品タイプ : 通常商品 */ public static $NORMAL; /** 商品タイプ : 特別商品 */ public static $SPECIAL; /** 商品タイプ : 限定商品 */ public static $LIMITED; /** コード値 */ private $code; /** 記述 */ private $description; /** コンストラクタ : 商品タイプの初期化 */ private function __construct($code, $description){ $this->code = $code; $this->description = $description; } public static function setup(){ //各クラスプロパティに商品タイプのインスタンスをセットアップして //valuesで使えるように基底クラスに保存する parent::add( self::$NORMAL = new ItemType("1","通常商品"), self::$SPECIAL = new ItemType("2","特別商品"), self::$LIMITED = new ItemType("3","限定商品") ); } /** コード値getter */ public function getCode(){ return $this->code; } /** 記述文字列getter */ public function getDescription(){ return $this->description; } } ItemType::setup(); //←これを実行しないと動かない
実行
<?php foreach(ItemType::values() as $itemType){ echo "コード値 : {$itemType->getCode()} 表記名 : {$itemType->getDescription()}\n"; } echo ItemType::$NORMAL->getDescription() . "\n";
2011-07-12 追記
結局業務ではこんな感じで落ち着きました。
enumクラス
<?php class ItemType { /** @var int コード値 */ private $code; /** @var string 記述 */ private $description; /** * コンストラクタ * @param int $code コード値 * @param string $description 記述 */ private function __construct($code, $description){ $this->code = $code; $this->description = $description; } /** * @return int コード値 */ public function getCode(){ return $this->code; } /** * @return string 記述 */ public function getDescription(){ return $this->description; } /** * @return boolean 等価かどうか */ public function equals(ItemType $itemType){ return $this->getCode() === $itemType->getCode(); } /** * 通常商品 */ public static function NORMAL(){ return new self(1, "通常商品"); } /** * 特別商品 */ public static function SPECIAL(){ return new self(2, "特別商品"); } /** * 限定商品 */ public static function LIMITED(){ return new self(3, "限定商品"); } }
実行
<?php $normal = ItemType::NORMAL(); $special = ItemType::SPECIAL(); if($normal->equals($special)){ echo "同じだよ"; }else{ echo "違うよ"; }
値を変えられる点と::setup()を実行しなきゃいけない点はクリアになったけれど
バリエーションを増やすごとにメソッド増やさなきゃいけないのが面倒くさい…ぐぬぬ。