Im Rahmen der Beschreibung des Themenbereichs sind Konzepte mit einer begrenzten Anzahl von Bedeutungen üblich. Aufzählungen sind dafür am besten geeignet. PHP verfügt nicht über spezielle Konstrukte zur Beschreibung einer Aufzählung, kann jedoch mithilfe eines objektorientierten Ansatzes nachgeahmt werden.
Einfachste Implementierung
Im einfachsten Fall können Sie eine Aufzählung als Wrapper-Objekt über einen einfachen Typ implementieren, indem Sie die Eingabeargumente programmgesteuert einschränken. Als Beispiel können Sie die Jahreszeiten nehmen, von denen es vier und nur vier gibt.
class Season
{
public const SUMMER = 'summer';
public const AUTUMN = 'autumn';
public const WINTER = 'winter';
public const SPRING = 'spring';
private string $value;
public function __construct(string $value)
{
if (
self::SUMMER !== $value &&
self::AUTUMN !== $value &&
self::WINTER !== $value &&
self::SPRING !== $value
) {
throw new InvalidArgumentException(sprintf(
"Wrong season value. Awaited '%s', '%s', '%s' or '%s'.",
self::SUMMER,
self::AUTUMN,
self::WINTER,
self::SPRING
));
}
$this->value = $value;
}
Sie können den Prozess des Erstellens einer Aufzählung mit einem Test demonstrieren.
public function testCreation(): void
{
$summer = new Season(Season::SUMMER);
$autumn = new Season(Season::AUTUMN);
$winter = new Season(Season::WINTER);
$spring = new Season(Season::SPRING);
$this->expectException(InvalidArgumentException::class);
$wrongSeason = new Season('Wrong season');
}
-. toValue() getValue(). , , __toString().
public function __toString(): string
{
return $this->value;
}
__toString() - .
public function testStringConcatenation(): void
{
$autumn = new Season(Season::AUTUMN);
$spring = new Season(Season::SPRING);
$value = $autumn . ' ' . $spring;
$this->assertIsString($value);
$this->assertSame(Season::AUTUMN . ' ' . Season::SPRING, $value);
}
PHP , . , , , .
public function testEquality(): void
{
$firstSummer = new Season(Season::SUMMER);
$secondSummer = new Season(Season::SUMMER);
$winter = new Season(Season::WINTER);
$this->assertTrue($firstSummer == $secondSummer);
$this->assertFalse($firstSummer == $winter);
$this->assertFalse($firstSummer === $secondSummer);
$this->assertFalse($firstSummer === $winter);
}
equals.
public function equals(Season $season): bool
{
return $this->value === $season->value;
}
public function testEquals(): void
{
$firstSummer = new Season(Season::SUMMER);
$secondSummer = new Season(Season::SUMMER);
$firstWinter = new Season(Season::WINTER);
$secondWinter = new Season(Season::WINTER);
$this->assertTrue($firstSummer->equals($secondSummer));
$this->assertTrue($firstWinter->equals($secondWinter));
$this->assertFalse($firstSummer->equals($secondWinter));
}
: Season . .
: . xlr 3pin, jack, mini jack usb .
class MicrophoneConnector
{
public const XLR_3PIN = 'xlr_3pin';
public const JACK = 'jack';
public const MINI_JACK = 'mini_jack';
public const USB = 'usb';
private string $value;
private function __construct(string $value)
{
$this->value = $value;
}
public function __toString(): string
{
return $this->value;
}
. . .
public static function xlr3pin(): self
{
return new self(self::XLR_3PIN);
}
jack, miniJack usb.
public function testEquality(): void
{
$firstJack = MicrophoneConnector::jack();
$secondJack = MicrophoneConnector::jack();
$xlr3pin = MicrophoneConnector::xlr3pin();
$this->assertTrue($firstJack == $secondJack);
$this->assertFalse($firstJack == $xlr3pin);
$this->assertFalse($firstJack === $secondJack);
$this->assertFalse($firstJack === $xlr3pin);
}
, . .
: . , , , . agree, disagree hold.
class Decision
{
public const AGREE = 'agree';
public const DISAGREE = 'disagree';
public const HOLD = 'hold';
private string $value;
private function __construct(string $value)
{
$this->value = $value;
}
private function __clone() { }
public function __toString(): string
{
return $this->value;
}
__clone(). .
private static $agreeInstance = null;
public static function agree(): self
{
if (null === self::$agreeInstance) {
self::$agreeInstance = new self(self::AGREE);
}
return self::$agreeInstance;
}
c agree disagree hold.
public function testEquality(): void
{
$firsAgree = Decision::agree();
$secondAgree = Decision::agree();
$firstDisagree = Decision::disagree();
$secondDisagree = Decision::disagree();
$this->assertTrue($firsAgree == $secondAgree);
$this->assertTrue($firstDisagree == $secondDisagree);
$this->assertFalse($firsAgree == $secondDisagree);
$this->assertTrue($firsAgree === $secondAgree);
$this->assertTrue($firstDisagree === $secondDisagree);
$this->assertFalse($firsAgree === $secondDisagree);
}
. __toString() . : . .
public static function from($value): self
{
switch ($value) {
case self::AGREE:
return self::agree();
case self::DISAGREE:
return self::disagree();
case self::HOLD:
return self::hold();
default:
throw new InvalidArgumentException(sprintf(
"Wrong decision value. Awaited '%s', '%s' or '%s'.",
self::AGREE,
self::DISAGREE,
self::HOLD
));
}
}
: . . : __sleep() __wakeup(). __sleep() . __wakeup() from() Decision.
class Order
{
private Decision $decision;
private string $description;
public function getDecision(): Decision
{
return $this->decision;
}
public function getDescription(): string
{
return $this->description;
}
public function __construct(Decision $decision, string $description)
{
$this->decision = $decision;
$this->description = $description;
}
public function __sleep(): array
{
return ['decision', 'description'];
}
public function __wakeup(): void
{
$this->decision = Decision::from($this->decision);
}
}
/ .
public function testSerialization(): void
{
$order = new Order(Decision::hold(), 'Some order description');
$serializedOrder = serialize($order);
$this->assertIsString($serializedOrder);
/** @var Order $unserializedOrder */
$unserializedOrder = unserialize($serializedOrder);
$this->assertInstanceOf(Order::class, $unserializedOrder);
$this->assertTrue($order->getDecision() === $unserializedOrder->getDecision());
}
, , . , , . , .
class Season
{
public const SEASONS = ['summer', 'autumn', 'winter', 'spring'];
private string $value;
public function __construct(string $value)
{
if (!in_array($value, self::SEASONS)) {
throw new InvalidArgumentException(sprintf(
"Wrong season value. Awaited one from: '%s'.",
implode("', '", self::SEASONS)
));
}
$this->value = $value;
}
.
: . .
class Size
{
public const SIZES = ['xxs', 'xs', 's', 'm', 'l', 'xl', 'xxl'];
private string $value;
private function __construct(string $value)
{
$this->value = $value;
}
public function __toString(): string
{
return $this->value;
}
public static function __callStatic($name, $arguments)
{
$value = strtolower($name);
if (!in_array($value, self::SIZES)) {
throw new BadMethodCallException("Method '$name' not found.");
}
if (count($arguments) > 0) {
throw new InvalidArgumentException("Method '$name' expected no arguments.");
}
return new self($value);
}
}
public function testEquality(): void
{
$firstXxl = Size::xxl();
$secondXxl = Size::xxl();
$firstXxs = Size::xxs();
$secondXxs = Size::xxs();
$this->assertTrue($firstXxl == $secondXxl);
$this->assertTrue($firstXxs == $secondXxs);
$this->assertFalse($firstXxl == $secondXxs);
$this->assertFalse($firstXxl === $secondXxl);
$this->assertFalse($firstXxs === $secondXxs);
$this->assertFalse($firstXxl === $secondXxs);
}
, , IDE __callStatic(). DocBlock', .
/**
* @method static Size xxs()
* @method static Size xs()
* @method static Size s()
* @method static Size m()
* @method static Size l()
* @method static Size xl()
* @method static Size xxl()
*/
class Size
{
, , , .
PECL- SPL SplEnum. SPL ( ).
PHP verfügt nicht über spezielle Konstrukte zur Beschreibung einer Aufzählung, kann jedoch mithilfe eines objektorientierten Ansatzes nachgeahmt werden. Die Verwendung der Aufzählung als Singleton bietet zwar einige Vorteile, weist jedoch einen kritischen Nachteil auf, der die Implementierung erheblich verkompliziert. Es sollte beachtet werden, dass dies weniger ein Aufzählungsimplementierungsproblem als vielmehr ein allgemeines Problem der Implementierung des "Singleton" -Musters in PHP ist. Verallgemeinerte Lösungen bieten praktisch keine Vorteile, da bestimmte Methoden noch in DocBlock beschrieben werden müssen.
Alle Beispiele sind auf GitHub .