2012-08-24 15 views
7

Czy istnieje sposób dynamicznego tworzenia stałych klas? Wiem, że to brzmi trochę dziwnie, ale pozwól mi wyjaśnić, co usiłuję zrobić:Dynamiczne stałe w PHP?

  • Mam klasy Enum kto atrybuty są definiowane przez statyczne const definicji
  • Ta klasa rozszerza klasę PHP SplEnum
  • Zamiast typu w każdej z tych definicji w kodzie Chciałbym mieć statyczny initialiser wychodzić do bazy danych i wyciągnąć wartości wyliczonych

Może latków tak:

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; 
     } 
    } 
} 

Rozumiem, że to nie zadziała, ponieważ nie ustawia CONST, lecz raczej statyczne. Może cały mój pomysł jest oparty na włosach i jest na to lepsza technika. W każdym razie, każda metoda osiągnięcia celu końcowego jest bardzo doceniana.

UPDATE

myślę, że może to być pomocne, aby być bardziej jasne, na moich celów, ponieważ myślę, że to całkiem możliwe, że moje użycie Stałe nie jest dobry. Zasadniczo chcę osiągnąć jest typowe wymagania listy wyliczonych za:

  1. funkcyjne Constrain podpisy. Chcę móc poprosić o "zestaw" wartości jako dane wejściowe do funkcji. Na przykład:

    public function do_something (ENUM_Types $ type) {}

  2. prosta i zwarta. Pozwól na prostą i zwartą składnię, jeśli jest używana w kodzie. Na przykład z wykorzystaniem stałych może napisać coś jak instrukcja warunkowa:

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

  3. dynamiczne wyliczanie. Chciałbym, żeby to wyliczenie było zarządzane przez frontend i przechowywane w bazie danych (używam screenów administratora wordpress w tym przypadku, gdyby ktoś miał na to ochotę). W czasie wykonywania ta "lista" powinna być wyciągnięta z bazy danych i udostępniona kodowi jako wyliczenie (lub podobna struktura, która osiąga powyższe cele).

+6

Z definicji stałej nie może być dynamiczny. Dlaczego po prostu nie używać zmiennych statycznych? – Matt

+0

No tak, wiem i dlatego powiedziałem, że "może wydawać się nieco dziwne". Zaktualizuję nieco pytanie, aby było jasne, co próbuję osiągnąć. – ken

+0

Innymi słowy ... nie chcesz dynamicznych stałych, chcesz dynamicznych wyliczeń. – EthanB

Odpowiedz

8

owinąć wartości "enum" w Singleton i wdrożenia (non-statycznego) magicznych __get metody:

<?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! 
    } 
} 

na punkty bonusowe, stworzyć (-oo non) funkcję, która zwraca pojedyncza:

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

Konsumenci "DynamicEnums" wyglądałby następująco:

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

[Edytuj ] Bardziej enumopodobne.

+0

Leniwa ocena, co? –

+1

+1 za magię ... –

+0

To wygląda dobrze. Wierzę, że spełnia wszystkie moje wymagania. Wielkie dzięki za magię. : ^) – ken

0

Możesz zrobić coś takiego, jak const = $$ stała. Wtedy możesz ustawić $ contant = cokolwiek innego. LUB możesz użyć chronionej właściwości, ponieważ chcesz, aby była dynamiczna, a stałe nie. Przykład:

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'); 
+0

Z definicji stała nie może być dynamiczna. To * musi * być ustawione na wartość dosłowną. – Matt

+0

Jak korzystać z chronionej właściwości i używać jej jak stałej Psuedo? –

+0

Czy możesz opisać, co masz na myśli w swojej odpowiedzi? – Matt

0

Nie polecam, ale eval() ... proszę nie.

Zmodyfikowałem autoloadery, aby automatycznie definiować typy wyjątków, których brakuje lub które zawierają błędy. Przyczyna: Możesz złapać niezatapiany wyjątek, ale nie możesz odzyskać PHP_FATAL podczas tworzenia literówki w klasie wyjątków.

7

P: Czy istnieje sposób dynamicznego tworzenia stałych klas?

Odpowiedź brzmi 'tak', ale nie rób tego :)

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; 

Następne pytanie ...

Q: Ograniczenie podpisy funkcyjnych. Chcę móc poprosić o "zestaw" wartości jako dane wejściowe do funkcji. Na przykład: public function do_something (ENUM_Types $type) {}

Według manual, w tym przypadku $type to musi być instancją klasy ENUM_Types. Ale na stałe jest niemożliwe (nie mogą zawierać przedmiotów).

Ale poczekaj ... Możemy wykorzystać taką sztuczkę:

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 

A potem możemy użyć "typów parametrów":

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

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

Q: Proste i Kompaktowy. Pozwól na prostą i zwartą składnię, jeśli jest używana w kodzie. Na przykład z wykorzystaniem stałych mógłbym napisać instrukcję warunkową coś takiego: if ($my_var === ENUM_Types::TypeA) {}

Można użyć wartości swoich pseudo-stałe w takiej formie:

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

Q: Dynamiczne wyliczanie. Chciałbym, żeby to wyliczenie było zarządzane przez frontend i przechowywane w bazie danych (używam screenów administratora wordpress w tym przypadku, gdyby ktoś miał na to ochotę). W czasie wykonywania ta "lista" powinna być wyciągnięta z bazy danych i udostępniona kodowi jako wyliczenie (lub podobna struktura, która osiąga powyższe cele).

Można init, swoje wyliczenie przekazując tablicę do EnumFactory::create($class, $constants):

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

wielkie dzięki. Wspaniale jest zobaczyć, jak można to osiągnąć, jeśli chcesz chodzić po ciemnej stronie (czyli ewaluacji). – ken