7

クラスの定数を動的に作成する方法はありますか? これは少し奇妙に聞こえるかもしれませんが、私がやろうとしていることを説明させてください:

  • 属性が静的const定義によって定義されている Enum クラスがあります
  • このクラスは PHP SplEnum クラスを拡張します
  • これらの各定義をコードに入力するのではなく、静的初期化子をデータベースに出して列挙値を取得したいと思います

多分このようなもの:

class myEnum extends SplEnum {
    public static function init () {
        $myNameValuePair = DB_Functions::get_enum_list();
        foreach ( $myNameValuePair as $name => $value) {
            $const = array ( self , $name );
            $const = $value;
        }
    }
}

CONSTではなく静的変数を設定するため、これは実際には機能しないことを認識しています。たぶん、私のアイデア全体は頭脳明晰であり、これにはもっと良いテクニックがあります. とにかく、最終目標を達成するための方法は大歓迎です。

アップデート

定数の使用が適切ではない可能性は十分にあると思うので、私の目標をもう少し明確にすることが役立つかもしれないと思います。基本的に私が達成したいのは、列挙リストの要件の典型です:

  1. 関数シグネチャを制約します。関数への入力として値の「セット」を要求できるようにしたいと考えています。例えば:

    public function do_something ( ENUM_Types $type ) {}

  2. シンプルでコンパクト。コードで使用する場合は、シンプルでコンパクトな構文を使用できます。たとえば、定数を使用して、次のような条件ステートメントを書くことができます。

    if ( $my_var === ENUM_Types::TypeA ) {}

  3. 動的列挙。この列挙をフロントエンドで管理し、データベースに保存したいと思います(誰かが気にする場合に備えて、これにはワードプレスの管理画面を使用しています)。実行時に、この「リスト」は DB から取り出され、列挙 (または上記の目標を達成する同様の構造) としてコードで使用できるようにする必要があります。

4

4 に答える 4

9

「列挙」値をシングルトンでラップし、(非静的) マジック__getメソッドを実装します。

<?php
class DynamicEnums {

  private static $singleton;

  private $enum_values;

  public static function singleton() {
    if (!self::$singleton) {
        self::$singleton = new DynamicEnums();
    }
    return self::$singleton;
  }

  function __construct() {
    $this->enum_values = array( //fetch from somewhere
        'one' => 'two',
        'buckle' => 'my shoe!',
    );
  }

  function __get($name) {
    return $this->enum_values[$name]; //or throw Exception?
  }

  public static function values() {
    return self::singleton()->enum_values; //warning... mutable!
  }
}

ボーナス ポイントを得るには、シングルトンを返す (OO 以外の) 関数を作成します。

function DynamicEnums() {
    return DynamicEnums::singleton();
}

「DynamicEnums」の消費者は次のようになります。

echo DynamicEnums::singleton()->one;
echo DynamicEnums()->one;            //can you feel the magic?
print_r(DynamicEnums::values());

[編集] より列挙型に似ています。

于 2012-08-24T21:27:20.093 に答える
7

Q: クラスの定数を動的に作成する方法はありますか?

答えは「はい」ですが、そうしないでください:)

class EnumFactory {

   public static function create($class, array $constants) {
       $declaration = '';
       foreach($constants as $name => $value) {
           $declaration .= 'const ' . $name . ' = ' . $value . ';';
       }
       eval("class $class { $declaration }");
   }

}

EnumFactory::create('darkSide', array('FOO' => 1, 'BAR' => 2));
echo darkSide::FOO . ' ' . darkSide::BAR;

次の問題...

Q: 関数のシグネチャを制限します。関数への入力として値の「セット」を要求できるようにしたいと考えています。例えば:public function do_something ( ENUM_Types $type ) {}

マニュアルによると、その場合$typeENUM_Typesクラスのインスタンスでなければなりません。しかし、定数の場合は不可能です (オブジェクトを含めることはできません)。

しかし、待ってください...次のようなトリックを使用できます。

class Enum {

    protected static $_constantToClassMap = array();
    protected static function who() { return __CLASS__; }

    public static function registerConstants($constants) {
        $class = static::who();
        foreach ($constants as $name => $value) {
            self::$_constantToClassMap[$class . '_' . $name] = new $class();
        }
    }

    public static function __callStatic($name, $arguments) {
        return self::$_constantToClassMap[static::who() . '_' . $name];
    }

}

class EnumFactory {

    public static function create($class, $constants) {
        $declaration = '';
        foreach($constants as $name => $value) {
            $declaration .= 'const ' . $name . ' = ' . $value . ';';
        }

        eval("class $class extends Enum { $declaration protected static function who() { return __CLASS__; } }");
        $class::registerConstants($constants);
    }

}

EnumFactory::create('darkSide', array('FOO' => 1, 'BAR' => 2));
EnumFactory::create('aaa', array('FOO' => 1, 'BAR' => 2));

echo (aaa::BAR() instanceof aaa) ? 'Yes' : 'No'; // Yes
echo (aaa::BAR() instanceof darkSide) ? 'Yes' : 'No'; // No

その後、「型ヒント」を使用できます。

function doSomething(darkSide $var) {
    echo 'Bu!';
}

doSomething(darkSide::BAR());
doSomething(aaa::BAR());

Q: シンプルでコンパクト。コードで使用する場合は、シンプルでコンパクトな構文を使用できます。たとえば、定数を使用して、次のような条件ステートメントを書くことができます。if ( $my_var === ENUM_Types::TypeA ) {}

次の形式で疑似定数の値を使用できます。

if (darkSide::FOO === 1) {}

Q: 動的列挙。この列挙をフロントエンドで管理し、データベースに保存したいと思います(誰かが気にする場合に備えて、これにはワードプレスの管理画面を使用しています)。実行時に、この「リスト」は DB から取り出され、列挙 (または上記の目標を達成する同様の構造) としてコードで使用できるようにする必要があります。

に配列を渡すことで、列挙を開始できますEnumFactory::create($class, $constants)

EnumFactory::create('darkSide', array('FOO' => 1, 'BAR' => 2));
于 2012-08-24T22:53:09.010 に答える
0

お勧めしませんが、 eval() ... しないでください。

オートローダーを変更して、欠落またはスペルミスのある例外タイプを自動的に定義しました。理由: キャッチされていない例外をキャッチすることはできますが、例外クラスでタイプミスをインスタンス化するときに PHP_FATAL から回復することはできません。

于 2012-08-24T20:35:16.323 に答える
0

Const = $$constant のようなことができます。次に、 $contant = なんでも設定できます。または、保護されたプロパティを動的にしたいが、定数はそうではないため、保護されたプロパティを使用できます。例:

class Foo {

protected $test = '';

function set($bar){
    $this->test = $bar;
}
function get($bar){
    return $this->test;
}


}

$foobar = new Foo();
$foobar->set('test');
echo $foobar->get('test');
于 2012-08-24T16:59:21.853 に答える