در علوم کامپیوتر و ریاضیات، Enumeration یا به اختصار Enum به لیستی از چندین آیتم مرتبط با یکدیگر اطلاق میگردد که در زبانهای برنامهنویسی مطرحی همچون جاوا، این مفهوم به صورت پیشفرض در هستهٔ این زبان پیادهسازی شده است. به طور کلی، چنین دیتا تایپی در زبان برنامهنویسی پیاچپی به صورت نِیتو وجود نداشت اما پس از عرضهٔ SPL، کلاسی تحت عنوان SplEnum
به لایبرری استاندارد این زبان افزوده شد تا با استفاده از آن بتوان از چنین دیتا تایپی در توسعهٔ نرمافزار استفاده نمود؛ البته لازم به یادآوری است که این کلاس به صورت پیشفرض با نصب پیاچپی روی سیستم نصب نخواهد شد و به صورت مجزا میباید آن را نصب نمود (جهت آشنایی بیشتر با مفهوم SPL، میتوانید به آموزش آشنایی با PHP Standard Library مراجعه نمایید.)
پیش از پرداختن به این کلاس، لازم به یادآوری است که گاهی میتوان از Constant به جای Enum استفاده نمود که چنین کاری مشکلات خاص خود را خواهد داشت که برای درک بهتر این موضوع، در ادامه ابتدا در فضای لوکالهاست پروژهای با نامی دلخواه همچون enum
ساخته سپس فایلی به نام composer.json
حاوی ساختار زیر در مسیر روت این پروژه ایجاد میکنیم:
{}
همانطور که ملاحظه میشود، یک آبجکت خالی ایجاد کردهایم؛ سپس کامند زیر را اجرا میکنیم:
/var/www/enum$ composer dump-autoload -o
در صورت موفقیتآمیز بودن کامند فوق، خواهیم دید که پوشهای جدید تحت عنوان vendor
در مسیر روت پروژه ساخته میشود که حاوی فایلی تحت عنوان autoload.php
است که با استفاده از آن به سادگی قادر خواهیم بود تا به صورت خودکار، کلاسهای مورد استفاده در جایجای پروژه را ایمپورت نماییم (جهت آشنایی بیشتر با پروسهٔ اُتولودینگ در زبان برنامهنویسی پیاچپی، میتوانید به آموزش آشنایی با مفاهیم Class و Object در متودولوژی OOP مراجعه نمایید.) حال در ادامه پوشهٔ دیگری تحت عنوان classes
در مسیر روت این پروژه ایجاد میکنیم که وظیفهٔ نگهداری کلاسهای مختلف را دارا است اما پیش از ساخت هر گونه کلاسی، مجدد به فایل composer.json
بازگشته و آن را به صورت زیر تکمیل میکنیم:
{
"autoload": {
"psr-4": {
"EnumSample\\": "classes"
}
}
}
در واقع، بر اساس استاندارد PSR-4 نِیماِسپیسی با نامی دلخواه همچون EnumSample
ساخته که به پوشهٔ classes
اشاره دارد (در همین راستا، توصیه میشود برای کسب اطلاعات بیشتر در این خصوص به آموزش آشنایی با مفهوم PHP Standard Recommendation مراجعه نمایید.) در ادامه، داخل پوشهٔ classes
فایلی به نام User.php
حاوی محتویات زیر میسازیم:
<?php
namespace EnumSample;
class User
{
const GENDER_MALE = 0;
const GENDER_FEMALE = 1;
const STATUS_INACTIVE = 0;
const STATUS_ACTIVE = 1;
}
پس از تعریف نِیماِسپیس، در بلوک کد فوق کلاسی ساختهایم تحت عنوان User
که در آن چهار کانستنت مختلف ایجاد کردهایم که در دو گروه اِلِمان مختلف تقسیمبندی شدهاند که عبارتند از *_GENDER
و *_STATUS
و هر کدام از آنها حاوی یک سری تنظیمات برای به ترتیب «جنسیت» و «وضعیت» آبجکتی از جنس یوزر میباشند. به نوعی میتوان هر کدام از گروههای فوق را به عنوان یک Enum در نظر گرفت و همانطور که پیش از این اشاره کردیم، این اصطلاح به مجموعهاز از اِلِمانهای مختلف اما مرتبط با هم اشاره دارد. حال در ادامه فایل دیگری میسازیم به نام UserFactory.php
و کدهای زیر را داخل آن مینویسیم:
<?php
namespace EnumSample;
class UserFactory
{
public function create(string $email, int $gender, int $status)
{
return "user email is: " . $email . "\nand gender is: " . $gender . "\nand status is: " . $status . "\n";
}
}
کلاس UserFactory
وظیفهٔ ساخت یک کاربر جدید را بر عهده دارد و برای همین منظور هم داخل آن متدی تحت عنوان ()create
نوشتهایم که سه پارامتر ورودی میگیرد و داخل این متد صرفاً مقادیر پارامترهای ورودی را ریترن کردهایم. حال خارج از پوشهٔ classes
و در مسیر روت پروژه، فایل دیگری میسازیم به نام index.php
و داخل آن آبجکت جدیدی از روی این کلاس میسازیم:
<?php
require_once "vendor/autoload.php";
$newUser = new EnumSample\UserFactory();
echo $newUser->create('hi@example.com', EnumSample\User::GENDER_MALE, EnumSample\User::STATUS_INACTIVE);
همانطور که ملاحظه میشود، ابتدا به ساکن فایل autoload.php
را با استفاده از دستور require_once
ایمپورت کردهایم سپس از روی کلاس UserFactory
آبجکتی به نام newUser$
ساخته و در خط آخر هم با فراخوانی متد ()create
و پاس دادن یک سری آرگومان، این متد را تکمیل کردهایم و در صورتی که این فایل را اجرا کنیم، در خروجی خواهیم دید:
PHP Fatal error: Uncaught Error: Class 'EnumSample\UserFactory' not found in /var/www/enum/index.php:4
متن ارور حاکی از آن است که کلاسی تحت عنوان UserFactory
با نِیماِسپیس EnumSample
شناخته نشده است که برای رفع این مشکل، کامند زیر را اجرا میکنیم:
$ composer dump-autoload -o
کاری که این دستور انجام میدهد آن است که کلاسهای جدید که داخل پروژهٔ خود ایجاد کردهایم را به رسمیت خواهد شناخت و اگر اکنون مجدد این فایل را اجرا کنیم، به عنوان خروجی خواهیم داشت:
user email is: hi@example.com
and gender is: 0
and status is: 0
در ارتباط با آرگومانهای دوم و سوم این متد باید گفت که از کانستنتهای موجود داخل کلاس User
استفاده نمودهایم و در نگاه اول این کد به درستی کار میکند اما مشکل اینجا است که با توجه به در نظر گرفتن مقدار صفر برای کانستنتهای GENDER_MALE
و STATUS_INACTIVE
، حتی اگر توسعهدهنده سهواً جای این دو آرگومان را اشتباه در نظر گیرد، کد به صورت کاملاً تصادفی باز هم درست کار خواهد کرد به طوری که مثلاً داریم:
echo $newUser->create('hi@example.com', EnumSample\User::STATUS_INACTIVE, EnumSample\User::GENDER_MALE);
همچنین با توجه به این که از قابلیت Type Hinting زبان برنامهنویسی پیاچپی استفاده ننمودهایم، متد فوق را به صورت زیر نیز میتوان بدون هیچ گونه مشکلی کال نمود:
echo $newUser->create('hi@example.com', 2, 3);
و به عنوان خروجی نیز خواهیم داشت:
user email is: hi@example.com
and gender is: 2
and status is: 3
برای رفع این معضل، میتوان با استفاده از کلاس SplEnum
کدهای اصولیتری اما آنچه در ادامه قصد داریم مورد بررسی قرار دهیم، یک لایبرری اپنسورس است تحت عنوان PHP Enum میباشد که با الهام از کلاس فوق توسعه یافته است.
راهنمای نصب لایبرری PHP Enum
به منظور نصب این لایبرری، نیاز است تا دستور زیر را در مسیر روت پروژه اجرا نماییم:
$ composer require myclabs/php-enum
چنانچه پروسهٔ نصب بدون هیچ گونه مشکلی تکمیل گردد، در نهایت فایل composer.json
به صورت زیر آپدیت خواهد شد:
{
"autoload": {
"psr-4": {
"EnumSample\\": "classes"
}
},
"require": {
"myclabs/php-enum": "^1.7"
}
}
از این پس ساختار پروژه به صورت زیر است:
enum
├── classes
│ ├── UserFactory.php
│ └── User.php
├── composer.json
├── composer.lock
├── index.php
└── vendor
├── autoload.php
├── composer
│ ├── autoload_classmap.php
│ ├── autoload_namespaces.php
│ ├── autoload_psr4.php
│ ├── autoload_real.php
│ ├── autoload_static.php
│ ├── ClassLoader.php
│ ├── installed.json
│ └── LICENSE
└── myclabs
└── php-enum
├── composer.json
├── LICENSE
├── README.md
└── src
├── Enum.php
└── PHPUnit
└── Comparator.php
حال مجدد به کلاس User
بازگشته و آن را به صورت زیر ریفکتور مینماییم:
<?php
namespace EnumSample;
use MyCLabs\Enum\Enum;
class User extends Enum
{
private const GENDER_MALE = 0;
private const GENDER_FEMALE = 1;
private const STATUS_INACTIVE = 0;
private const STATUS_ACTIVE = 1;
}
همانطور که ملاحظه میشود، از این پس کلاس User
کلیهٔ خصوصیات خود را از کلاس Enum
که مرتبط با لایبرری PHP Enum است ارثبری خواهد کرد. در ادامه، قابلیت Type Hintingرا در کلاس UserFactory
به صورت زیر عملی میسازیم:
<?php
namespace EnumSample;
use EnumSample\User;
class UserFactory
{
public function create(string $email, User $gender, User $status)
{
return "user email is: " . $email . "\nand gender is: " . $gender . "\nand status is: " . $status . "\n";
}
}
در حقیقت، به عنوان تایپ پارامترهای دوم و سوم متد ()create
به جای کیورد int
یا عدد صحیح، از نام کلاس User
استفاده نمودهایم به طوری با اجرای فایل index.php
حاوی کدهای زیر:
<?php
require_once __DIR__ . "/vendor/autoload.php";
$newUser = new EnumSample\UserFactory();
echo $newUser->create('hi@example.com', 2, 3);
با ارور زیر مواجه خواهیم شد:
PHP Fatal error: Uncaught TypeError: Argument 2 passed to EnumSample\UserFactory::create() must be an instance of EnumSample\User, int given, called in /var/www/enum/index.php on line 5 and defined in /var/www/enum/classes/UserFactory.php:8
متن ارور فوق حاکی از آن است که آرگومانهای دوم و سوم متد ()create
میباید از جنس کلاس User
باشند اما دادههایی از جنس عدد صحیح پاس داده شده است. در واقع، میبینیم که با استفاده از این لایبرری به سادگی میتوان قابلیت Type Hinting را به پروژه افزود (جهت کسب اطلاعات بیشتر در این رابطه، میتوانید به آموزش آشنایی با مفهوم Type Hinting در زبان PHP مراجعه نمایید.) حال مجدد فایل index.php
را به صورت زیر آپدیت میکنیم:
<?php
require_once __DIR__ . "/vendor/autoload.php";
$newUser = new EnumSample\UserFactory();
echo $newUser->create('hi@example.com', EnumSample\User::GENDER_MALE(), EnumSample\User::STATUS_INACTIVE());
همانطور که ملاحظه میشود، یکی از قابلیتهای لایبرری PHP Enum آن است که به صورت خودکار متدهایی از جنس استاتیک به منظور دستیابی به کانستنتها ساخته است به طوری که برای مثال متدی تحت عنوان ()GENDER_MALE
که داخل کلاس User
وجود خارجی ندارد و پشت پرده ساخته میشود، مقدار کانستنت GENDER_MALE
را ریترن میکند.
جمعبندی
اساساً میتوان گفت که Enum در فرآیند توسعهٔ نرمافزار این امکان را در اختیارمان میگذارد تا بتوانیم دیتا تایپی خاص تعریف نموده و یک سری اِلِمان مرتبط با یکدیگر را در آنها ذخیره ساخت و این در حالی است که بهکارگیری لایبرری PHP Enum این تضمین را میدهد که بتوانیم با استفاده از قابلیت Type Hinting زبان برنامهنویسی پیاچپی، متدها را موظف به دریافت دقیقاً همان دیتا تایپی سازیم که مد نظر داریم.