آموزش نحوهٔ استفاده از Enumeration در زبان PHP

آموزش نحوهٔ استفاده از Enumeration در زبان PHP

در علوم کامپیوتر و ریاضیات، 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 زبان برنامه‌نویسی پی‌اچ‌پی، متدها را موظف به دریافت دقیقاً همان دیتا تایپی سازیم که مد نظر داریم.

از بهترین نوشته‌های کاربران سکان آکادمی در سکان پلاس


online-support-icon