PHP Manual
/
Datové struktury

Datový typ Enum objekt v PHP

29. 05. 2022

Obsah článku

Od PHP 8.1 lze použít datový typ Enum, který slouží pro definici přesných výčtových hodnot seznamu. Hodí se to pro případy, kdy víme, že hodnota proměnné může nabývat jen konkrétních několika hodnot.

Například takto ukládám typy notifikací:

enum OrderNotificationType: string
{
case Email = 'email';
case Sms = 'sms';
}

Datový typ Enum je v PHP klasický objekt, který se chová jako speciální typ konstanty, ale navíc má instanci, kterou můžeme předávat dál. Na rozdíl od běžného objektu se na něj ale vztahuje řada omezení.

Rozdíly Enumu a objektů

Přestože jsou enumy postaveny na třídách a objektech, nepodporují všechny funkce související s objekty. Zejména je zakázáno, aby objekty enumů měly vnitřní stav (vždy musí jít o statickou třídu).

Konkrétní výčet rozdílů:

  • Zakázány jsou konstruktory a destruktory.
  • Dědičnost není podporována. Enumy nelze rozšiřovat ani dědit jinou třídou.
  • Statické nebo objektové vlastnosti nejsou povoleny.
  • Klonování konkrétních hodnot (případů) Enum není podporováno, každý jednotlivý případ musí být singletonové instance.
  • Magické metody, s výjimkou níže uvedených, jsou zakázány.

Následující funkce objektu jsou k dispozici a chovají se stejně jako u jakéhokoli jiného objektu:

  • Veřejné, soukromé a chráněné metody.
  • Veřejné, soukromé a chráněné statické metody.
  • Veřejné, soukromé a chráněné konstanty.
  • Enumy mohou implementovat libovolný počet rozhraní.
  • K enumům a případům mohou být připojeny atributy. Cílový filtr TARGET_CLASS zahrnuje samotné Enumy. Cílový filtr TARGET_CLASS_CONST zahrnuje případy Enum.
  • Magické metody __call, __callStatic a __invoke.
  • Konstanty __CLASS__ a __FUNCTION__ se chovají jako normální konstanty
  • Magická konstanta ::class na typu Enum se vyhodnocuje jako celý název datového typu včetně případného jmenného prostoru, přesně stejně jako u objektu. Magická konstanta ::class na instanci typu Case se také vyhodnocuje jako typ Enum, protože se jedná o instanci jiného typu.

Použití Enumu jako datový typ

Představte si, že máme enum reprezentující druhy obleků. V takovém případě stačí definovat typ Suit a uložit jednotlivé validní hodnoty.

Instanci konkrétní možnosti pak získáme klasicky přes čtyřtečku, jako při práci se statickou konstantou.

Ukázka definici Enumu, jeho vyvolání podle konkrétního typu a předání do funkce:

enum Suit
{
case Hearts;
case Diamonds;
case Clubs;
case Spades;
}
function doStuff(Suit $s)
{
// ...
}
doStuff(Suit::Spades);

Porovnání dvou hodnot

Zásadní výhoda enumu oproti objektům a konstantám je ta, že lze snadno porovnávat jejich hodnotu.

Základní porovnání, že pracujeme s konkrétní hodnotou můžeme udělat takto:

$a = Suit::Spades;
$b = Suit::Spades;
$a === $b; // true

Velmi často také potřebujeme rozhodnout, že konkrétní hodnota patří do validního výčtu hodnot Enumu. To lze ověřit snadno takto:

$a = Suit::Spades;
$a instanceof Suit; // true

Přečtení hodnoty typu

Konkrétní hodnotu typu můžeme přečíst buď jako název volací konstanty, nebo přímo reálnou definovanu hodnotu (pokud existuje):

enum Colors
{
case Red;
case Blue;
case Green;
public function getColor(): string
{
return $this->name;
}
}
function paintColor(Colors $colors): void
{
echo "Paint: " . $colors->getColor();
}

Hodnota volací konstanty se čte přes property name. Důležité je také to, že přímo do datového typu Enum lze implementovat vlastní funkci, kterou můžeme nad každým Enumem zavolat.

Pokud konkrétní Enum implementuje také reálné hodnoty (které se skrývají pod každou konstantou), lze přečíst i jejich hodnotu:

enum OrderNotificationType: string
{
case Email = 'email';
case Sms = 'sms';
}
$type = OrderNotificationType::Email;
echo $type->value;

Všechny validní hodnoty Enumu

Často potřebujeme (například uživateli v chybové hlášce) vypsat všechny možné hodnoty, kterých může Enum nabývat. Při použítí konstant toto možné nebylo, Enum to umožňuje snadno:

Suit::cases();

Vrátí: [Suit::Hearts, Suit::Diamonds, Suit::Clubs, Suit::Spades].

Ověření, že je proměnná typu Enum

Že konkrétní neznámá proměnná obsahuje Enum můžeme snadno ověřit podmínkou:

if ($haystack instanceof \BackedEnum) {

Každý Enum objekt je automaticky potomek obecného rozhraní \BackedEnum.

Další informace jsou v diskusi na GitHubu PhpStan: https://github.com/phpstan/phpstan/issues/7304

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
2.

Potřebujete poradit s PHP?

Nabízím trénink vývojářů, konzultace, školení a analýzu návrhových vzorů. Osobně v Praze nebo online.

Napište mi, pokud si nevíte rady.

Lektor: Jan Barášek

Status:
All systems normal.
2024