Autor Zpráva
Gren
Profil *
Ahoj, pokouším se vytvořit datový typ Enum, požadavkem je, aby fungoval type hinting. a chybí mi poslední krok. zatím mám toto:
class Item
{
    private $item;
    private $value;
    public function __construct($item, $value = null)
    {
        $this->item = $item;
        $this->value = $value;
    }
    
    public function getItem()
    {
        return $this->item;
    }
    
    
    public function getValue()
    {
        return $this->value;
    }
}
class Enum
{
    public static $items = array();
    private $item;
    private $value;
    private function __construct($item, $value)
    {
        $this->item = $item;
        $this->value = $value;
    }
    
    public static function SetItems(array $a)
    {
        foreach($a as $key => $value)
        {
            if(!is_numeric($key))
            {
                self::$items[$key] = new Item($key, $value);
            }else self::$items[$value] = new Item($value);
        }
    }
    
    
    public static function __callStatic($name, $argument) 
    {
        $item = self::$items[$name];
        return new Enum($item->getItem(), $item->getValue());
    }
}

Použití:
Enum::SetItems(array("Pondeli" => 1, "Utery" => 2, "Streda", "Ctvrtek"));
            var_dump(Enum::Pondeli());
Výpis:
object(Enum)#6 (2) { ["item":"Enum":private]=> string(7) "Pondeli" ["value":"Enum":private]=> int(1) }


Já bych ale potřeboval, aby se to tvářilo jako objekt, ale potom když bych to chtěl s něčím porovnávat, tak aby se to chovalo jako hodnota, nějak takto:
class DnyVTydnu extends Enum
{
  public function __construct()
  {
      $this->SetItems(array("Pondeli", "Utery", "Streda"));
   }
}

function Funkce(DnyVTydnu $den)
{
     if("Pondeli" == $den)
       echo "Dneska je zas pondělí";
}

$dny = new DnyVTydnu();
Funkce($dny::Pondeli());

Nenapadá někoho jak to dořešit? Díky
Jan Tvrdík
Profil
Gren:
Kód jsem nečetl, jenom připojuji odkaz php.vrana.cz/vyctovy-typ.php.
Gren
Profil *
No řešení pana Vrány mi přijde dost kostrbaté. to moje je řekl bych elegantnější, problém je, že potřebuju aby mi vracel instanci Enum, ale když bych chtěl provést porovnání, aby tam už byla hodnota, tedy nemusel jsem volat nějakou pomocnou metodu...jde mi o to jak tenhle můj celkem jednoduchý způsob ještě trochu zefektivnit...
Tori
Profil
Gren:
když bych to chtěl s něčím porovnávat, tak aby se to chovalo jako hodnota
Záleží i na tom, s čím to budete porovnávat. Pokud s řetězcem, tak se objekt přetypuje na řetězec (= můžete využít metodu __toString). Při porovnávání s číslem to ale selže. Vlastně - chcete porovnávat i hodnotu v $value? Pokud ne, tak by stačilo i if ($den->item == 'Pondeli').
Gren
Profil *
jo tento problém jsem už vyřešil. používám toString, ale mám ted jiný problém. že ta metoda call vrací instanci Enum a ne instanci třídy toho aktuálního výčtu. takže v ta funkce musí vypadat takto: function Funkce(Enum e) a to je samozřejmě špatně...nevíte co s tím?
Kod jsem trošku poupravil:
class Item
{
    private $item;
    private $value;
    public function __construct($item, $value = null)
    {
        $this->item = $item;
        $this->value = $value;
    }
    
    public function getItem()
    {
        return $this->item;
    }
    
    
    public function getValue()
    {
        return $this->value;
    }
}
class Enum
{
    public $items = array();
    private $item;
    private $value;
    private function __construct($item, $value)
    {
        $this->item = $item;
        $this->value = $value;
    }
    
    public function SetItems(array $a)
    {
        foreach($a as $key => $value)
        {
            if(!is_numeric($key))
            {
                $this->items[$key] = new Item($key, $value);
            }else $this->items[$value] = new Item($value);
        }
    }
    
    
    public function __toString() {
        if(!isset($this->value))
            return (string)$this->item;
        return (string)$this->value;
    }
    
    
    public function __get($name)
    {
//        $x = get_called_class(); Možná by šlo nějak použít toto
//        return new $x;
        $item = $this->items[$name];
        return new Enum($item->getItem(), $item->getValue());
    }
}

Použití:
class Days extends Enum
           {
               public function __construct()
               {
                   $this->SetItems(array("Pondeli" => 10, "Utery", "Streda"));
               }
           }
           $day = new Days();
           
           Funkce($day->Pondeli); //Mělo by vypsat 10, ale selže protože vkládám objekt Enum a ne Days
           
           function Funkce(Days $d)
           {
               echo $d;
           }

Nevím jak by se to dalo vyřešit. jsem schopný ve třídě Enum zjistit jaká třída jí volá (get_called_class) ale nevím jak to udělat tak aby každý ten výčet, který je potomkem Enum byl co nejjednodušší, tedy aby nemusel implementovat další metody, aby všechno vyřešil ten Enum...
Tori
Profil
Gren:
mám ted jiný problém. že ta metoda call vrací instanci Enum a ne instanci třídy toho aktuálního výčtu
A proč vlastně nepoužijete rovnou:

public function __get($name)
{
    if (isset($this->items[$name]))
        return $this->items[$name];
    else
        throw new InvalidArgumentException("Hodnota $name není v tomto výčtu povolena.");
}
?

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: