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


در مبحث شیئ‌گرایی در زبان پی‌اچ‌پی گاهی نیاز داریم تا برخی پراپرتی‌ها و متدها را به گونه‌ای طراحی کنیم که بدون نیاز به ساخت آبجکت از روی یک کلاس به‌بخصوص، بتوان آن‌ها را فراخوانی کرد که به این دست پراپرتی‌ها و متدها اصطلاحاً استاتیک گفته می‌شود و در این آموزش قصد داریم این مفهوم را به طور مفصل مورد بررسی قرار دهیم.

به خاطر داشته باشید
برخی توسعه‌دهندگان بر این باورند که استفاده از پراپرتی‌ها و متدهای استاتیک اصلاً روش خوبی نیست و تا حد ممکن از انجام این کار می‌باید جلوگیری کرد.

برای همین منظور، داخل پوشهٔ oop پروژه‌ای تحت عنوان static-keyword ایجاد کرده و با مد نظر قرار دادن ساختاری که این دورهٔ آموزشی مورد استفاده قرار داده‌ایم، شروع به تکمیل این پروژه می‌کنیم. برای شروع، داخل فولدر classes فایلی به نام User.php ساخته و آن را به صورت زیر تکمیل می‌کنیم:

<?php
namespace SokanAcademy;

class User
{
    public static $usersNo = 0;
}

داخل بدنهٔ‌ کلاس User یک پراپرتی تعریف کرد‌ه‌ایم تحت عنوان usersNo$ و مقدار اولیهٔ ۰ را برای آن در نظر گرفته‌ایم. آنچه در ارتباط با این پراپرتی نسبت به پراپرتی‌هایی که تا این مرحله از دوره مورد استفاده قرار داده‌ایم متفاوت است، به‌کارگیریِ کلیدواژهٔ static قبل از نام پراپرتی است. در ادامه، وارد فایل index.php شده و آن را به صورت زیر تکمیل می‌کنیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

echo SokanAcademy\User::$usersNo;

همان‌طور که می‌بینیم، به منظور فراخوانی پراپرتی‌هایی که از جنس static هستند، می‌باید نام کلاس را نوشته سپس علائم :: را قرار داد و نام پراپرتی با در نظر گرفتن علامت $ را وارد کرد.

نکته
علائم :: تحت عنوان Scope Resolution Operator نامیده می‌شوند.

اگر بخواهیم کدهای فوق را به شکل بهتری ریفکتور کنیم نیز خواهیم داشت:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
use SokanAcademy\User;
echo User::$usersNo;

می‌بینیم که ابتدا کلاس User به همراه نِیم‌اِسپیس آن را به اصطلاح use کرده سپس در حین استفاده از این کلاس فقط و فقط نام آن را درج نموده‌ایم. حال مجدد به کلاس User بازگشته و آن را به صورت زیر تکمیل‌تر می‌کنیم:

<?php
namespace SokanAcademy;

class User
{
    public static $usersNo = 0;

    public static function addToUsersNo()
    {
        self::$usersNo++;
    }
}

متدی نوشته‌ایم به نام ()addToUsersNo و داخل بدنهٔ این متد به منظور فراخوانی تنها پراپرتی موجود در این کلاس، دستور self را نوشته سپس علائم :: را قرار داده و در نهایت نام کامل پراپرتی userNo$ با در نظر گرفتن علامت $ را نوشته‌ایم سپس با درج علائم ++ مقدار موجود در پارامتر no$ را یک واحد افزوده‌ایم.

نکته
توجه داشته باشیم در متدها و پراپرتی‌هایی که استاتیک نیستند با استفاده از دستور this$ به پراپرتی‌ها دست می‌یابیم اما وقتی پراپرتی و متدی استاتیک باشد، می‌باید از دستور ::self استفاده نماییم.

به منظور آشنایی با نحوهٔ فراخوانی این متد، مجدد به فایل index.php بازگشته و آن را به صورت زیر تغییر می‌دهیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
use SokanAcademy\User;
echo User::$usersNo;
echo "\n";
User::addToUsersNo();
echo User::$usersNo;
echo "\n";

به عنوان خروجی هم خواهیم داشت:

/var/www/oop/static-keyword$ php index.php 
0
1

همان‌طور که می‌بینیم، همچون روشی که به منظور فراخوانی یک پراپرتی از جنس static از علائم :: استفاده نمودیم، برای فراخوانی متد ()addToUsersNo نیز پس از درج نام کلاس User علائم :: را نوشته سپس متد مذکور را به همراه آرگومانی از جنس عدد صحیح وارد کرده‌ایم.

نکتهٔ مهمی که در ارتباط با کیورد static وجود دارد آن است که داخل متدهای استاتیک هرگز نمی‌توان به پراپرتی‌های غیراستاتیک دست یافت. برای روشن‌تر شدن این موضوع، کلاس User را به صورت زیر تکمیل می‌کنیم:

<?php
namespace SokanAcademy;

class User
{
    public static $usersNo = 0;
    public $someProperty = "Some Property";

    public static function addToUsersNo()
    {
        self::$usersNo++;
    }

    public static function doSomething()
    {
        return $this->someProperty;
    }
}

همان‌طور که می‌بینیم، یک پراپرتی معمولی تحت عنوان someProperty$ ساخته سپس متدی از جنس static ساخته‌‌ایم به نام ()doSomething و خواسته‌ایم تا مقدار پراپرتی جدیدی که ساخته‌ایم را داخل آن ریترن کنیم. جهت تست، وارد فایل index.php شده و آن را به صورت زیر تغییر می‌دهیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
use SokanAcademy\User;
// echo User::$usersNo;
// echo "\n";
// User::addToUsersNo();
// echo User::$usersNo;
// echo "\n";
User::doSomething();

پس از کامنت کردن کدهای قبلی،‌ متد ()doSomething را فراخوانی کرده‌ایم اما در خروجی خواهیم داشت:

/var/www/oop/static-keyword$ php index.php 
PHP Fatal error:  Uncaught Error: Using $this when not in object context in /var/www/oop/static-keyword/classes/User.php:16

همان‌طور که در متن ارور ملاحظه می‌کنیم، گفته شده که امکان دسترسی به دستور this$ را نداریم و این مشکل از آنجا ناشی می‌شود که گفتیم متدهای static بدون نیاز به ساخت آبجکت می‌توانند فراخوانی شوند پس از همین روی ما با هیچ گونه آبجکتی سروکار نداریم و به همین دلیل هم می‌باشد که به دستور this$ نیز دسترسی نداریم.

اساساً یکی از کاربردهای پراپرتی‌های static آن است از آن‌ها به عنوان شمارنده (Counter) استفاده نماییم زیرا پراپرتی‌هایی از این دست توانایی آن را دارند تا آخرین مقداری که به آن‌ها اختصاص یافته را در خود ذخیره سازند. برای درک بهتر این موضوع، کدهای داخل فایل index.php را به صورت زیر تغییر می‌دهیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
use SokanAcademy\User;
echo User::$usersNo;
echo "\n";
User::addToUsersNo();
User::addToUsersNo();
User::addToUsersNo();
User::addToUsersNo();
User::addToUsersNo();
User::addToUsersNo();
User::addToUsersNo();
echo User::$usersNo;
echo "\n";

همان‌طور که می‌بینیم، ابتدا یک بار مقدار اولیهٔ پراپرتی usersNo$ را چاپ کرده‌ایم که برابر با ۰ است سپس چند بار پشت سر هم متد ()addToUsersNo را فراخوانی کرده‌ایم که وظیفهٔ افزودن یک واحد به مقدار قبلی پراپرتی مذکور را دارا است و در نهایت هم مجدد مقدار این پراپرتی را چاپ کرده‌ایم به طوری که در خروجی خواهیم داشت:

0
7

همچنین توجه داشته باشیم که متدهای استاتیک را می‌توان در داخل سایر متدها نیز فراخوانی نمود؛ به طور مثال،‌ کلاس User را به صورت زیر می‌توانیم تغییر دهیم:

<?php
namespace SokanAcademy;

class User
{
    public static $usersNo = 0;
    public $someProperty = "Some Property";

    public static function addToUsersNo()
    {
        self::$usersNo++;
    }

    public static function doSomething()
    {
        return $this->someProperty;
    }

    public function runAddToUsersNoMethod()
    {
        self::addToUsersNo();
    }
}

همان‌طور که می‌بینیم، متدی معمولی ساخته‌ایم تحت عنوان ()runAddToUsersNoMethod که داخلش به همان روشی که پراپرتی‌های استاتیک را فراخوانی می‌کردیم، با استفاده از علائم :: متد استاتیک ()addToUsersNo را کال کرده‌ایم. حال به فایل index.php مراجعه کرده و آن را به صورت زیر تغییر می‌دهیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
use SokanAcademy\User;

$user = new User();
$user->runAddToUsersNoMethod();
echo User::$usersNo;

ابتدا آبجکتی از روی کلاس User ساخته سپس با استفاده از آن متد ()runAddToUsersNoMethod را فراخوانی کرده‌ایم که داخل این متد، متد استاتیک ()addToUsersNo فراخوانی شده است. سپس در خط هشتم پراپرتی usersNo$ را چاپ کرده‌ایم.

در بحث وراثت نیز کلاس فرزند می‌تواند به پراپرتی‌ها و متدهای استاتیک کلاس والد دست یابد. برای روشن‌تر شدن این موضوع، داخل پوشهٔ classes فایلی به نام Author.php ساخته و آن را به صورت زیر تکمیل می‌کنیم:

<?php 
namespace SokanAcademy;

class Author extends User 
{
    public function getStaticUserNoProperty()
    {
        return User::$usersNo;
    }

    public function runStaticAddToUsersNoMethod()
    {
        return User::addToUsersNo();
    }
}

کلاسی ساخته‌ایم تحت عنوان Author که از کلاس User ارث‌بری می‌کند و داخل این کلاس دو متد نوشته‌ایم به طوری که متد اول تحت عنوان ()getStaticUserNoProperty وظیفهٔ فراخوانی پراپرتی استاتیک usersNo$ را دارا است که داخل کلاس والد User تعریف شده است و داخل متد ()runStaticAddToUsersNoMethod نیز خروجی متد استاتیک ()addToUsersNo ریترن شده است. حال وارد فایل index.php شده و آن را به صورت زیر تغییر می‌دهیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
use SokanAcademy\Author;

$author = new Author();
echo $author->getStaticUserNoProperty();
$author->runAddToUsersNoMethod();
echo $author->getStaticUserNoProperty();

ابتدا به ساکن یک آبجکت از روی کلاس Author تحت عنوان author$ ساخته‌ایم سپس متد ()getStaticUserNoProperty را فراخوانی کرده‌ایم به طوری که این متد مقدار اولیهٔ پراپرتی استاتیک usersNo$ که برابر با ۰ است را ریترن می‌کند. سپس متد ()runAddToUsersNoMethod را کال کرده‌ایم که داخلش متد استاتیک ()addToUsersNo فراخوانی شده که این وظیفه را دارا است تا یک واحد به مقدار پراپرتی usersNo$ بیفزاید و در نهایت مجدد متد ()getStaticUserNoProperty را فراخوانی کرده‌ایم به طوری که در خروجی خواهیم داشت:

01

در واقع،‌ ابتدا یک بار مقدار پراپرتی usersNo$ که به صورت پیش‌فرض ۰ است چاپ شده سپس از طریق متد ()runStaticAddToUsersNoMethod یک واحد به آن افزوده شده و در نهایت مجدد مقدار پراپرتی مذکور چاپ شده است. در عین حال توجه داشته باشیم که کلاس Author را به صورت زیر نیز می‌توان نوشت:

<?php 
namespace SokanAcademy;

class Author extends User 
{
    public function getStaticUserNoProperty()
    {
        return parent::$usersNo;
    }

    public function runStaticAddToUsersNoMethod()
    {
        return parent::addToUsersNo();
    }
}

همان‌طور که ملاحظه می‌شود، کلاس User با کیورد parent جایگزین شده است. در حقیقت، با توجه به این که کلاس User به عنوان والدِ کلاس Author قملداد می‌گردد، از همین روی کلیدواژهٔ parent برای همین منظور در هستهٔ زبان پی‌اچ‌پی گنجانده شده تا به جای درج نام کلاس والد، از این کیورد استفاده نمود.

نکته
مزیت استفاده از کیورد parent آن است که اگر بنا به هر دلیلی روزی نام کلاس والد (User) تغییر کرد، دیگر نیازی به آپدیت کردن مواردی که نام این کلاس داخل کلاس فرزند استفاده شده نخواهیم داشت و همین مسئله از بروز باگ‌های سهوی جلوگیری می‌کند.

یکی دیگر از کاربردهای متدهای static در پروسهٔ ساخت کلاس‌هایی است که اصطلاحاً Utility یا Helper گفته می‌شوند. به عبارت بهتر، این دست کلاس‌ها مصارفی همچون تبدیل واحد، نمایش تاریخ، ری‌دایرکت کردن کاربر، اعتبارسنجی داده‌ها و ... دارند که برای درک بهتر این موضوع، داخل پوشهٔ classes فایل جدیدی به نام Utility.php ساخته و آن را به صورت زیر تکمیل می‌کنیم:

<?php
namespace SokanAcademy;

class Utility
{
    public static function redirect(string $url)
    {
        header("Location: $url");
        exit;
    }
}

همان‌طور که می‌بینیم، متدی تحت عنوان ()redirect از جنس static ساخته که یک پارامتر ورودی تحت عنوان url$ می‌گیرد که تایپ هینت آن string است؛ به عبارتی،‌ فقط و فقط دیتایی از جنس استرینگ می‌توان به این متد پاس داد. سپس داخل این متد از فانکشن ()header زبان پی‌اچ‌پی استفاده نموده‌ایم که این وظیفه را دارا است تا یک هِدِر سِت کند و همان‌طور که می‌بینیم هِدِر Location را در نظر گرفته‌ایم که وظیفهٔ ری‌دایرکت کردن را دارد و به عنوان مقدار آن هم پارامتر ورودی url$ را در نظر گرفته‌ایم و در نهایت هم به منظور پایان دادن به این اسکریپت، از دستور exit استفاده کرده‌ایم. حال وارد فایل index.php شده و آن را به صورت زیر تغییر می‌دهیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

SokanAcademy\Utility::redirect('https://sokanacademy.com');

پس از فراخوانی متد ()redirect از کلاس Utility و اختصاص یک لینک،‌ می‌بینیم که به محض اجرای این فایل در مرورگر، به وب‌سایت سکان آکادمی ری‌دایرکت خواهیم شد.

حال برای آن که با کاربردهای متدهای استاتیک در یک به اصطلاح Use Case واقعی‌تر آشنا شویم، در ادامهٔ این آموزش قصد داریم تا ببینیم به چه شکل می‌توان یک کلاس مدیریت سِشِن با استفاده از متدهای استاتیک ساخت.

این بخش از محتوا مخصوص کاربرانی است که ثبت‌نام کرده‌اند.
جهت مشاهدهٔ این بخش از محتوا لاگین نمایید.

جمع‌بندی
در این آموزش با یک سری اصطلاحاً Use Case برای کلیدواژهٔ static در زبان پی‌اچ‌پی آشنا شده و دیدیم که با استفاده از این دستور به چه شکل می‌توانیم پراپرتی‌ها و متدهایی بسازیم که بدون نیاز به ساخت آبجکت از روی کلاس مذکور، امکان فراخوانی آن‌ها را داشته باشیم.

دانلود فایل‌های تمرین

لیست نظرات
کاربر میهمان
دیدگاه شما چیست؟
کاربر میهمان