في إطار وصف مجال الموضوع ، تعتبر المفاهيم ذات عدد محدود من المعاني شائعة. التعداد هو الأفضل لهذا. لا تحتوي PHP على بنيات خاصة لوصف التعداد ، ولكن يمكن تقليدها باستخدام نهج موجه للكائنات.
أبسط تنفيذ
في أبسط الحالات ، يمكن تنفيذ التعداد ككائن مجمّع على نوع بسيط ، عن طريق تقييد وسيطات الإدخال برمجيًا. على سبيل المثال ، يمكنك أن تأخذ الفصول ، التي يوجد منها أربعة وأربعة فقط.
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;
}
يمكنك توضيح عملية تكوين التعداد باختبار.
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 على بنيات خاصة لوصف التعداد ، ولكن يمكن تقليدها باستخدام نهج موجه للكائنات. على الرغم من أن استخدام التعداد كمفرد يوفر بعض المزايا ، إلا أن له عيبًا حاسمًا يعقد التنفيذ بشكل كبير. وتجدر الإشارة إلى أن هذه ليست مشكلة تنفيذ تعداد بقدر ما هي مشكلة عامة لتنفيذ نمط "مفرد" في PHP. لا تعطي الحلول المعممة أي مزايا عمليًا ، حيث لا يزال يتعين وصف طرق معينة في DocBlock.
جميع الأمثلة موجودة على GitHub .