سرفصل‌های آموزشی
آموزش OOP در PHP
آشنایی با متدهای به اصطلاح Magic در زبان PHP

آشنایی با متدهای به اصطلاح Magic در زبان PHP

یک سری متد پیش‌فرض در هستهٔ زبان پی‌اچ‌پی وجود دارند که نام آن‌ها با علائم __ شروع می‌گردد که این دست متدها تحت عنوان Magic (جادویی) شناخته می‌شوند که ()construct__ یکی از رایج‌ترین آن‌ها است که در آموزش گذشته با کارکرد آن‌ آشنا شدیم. در این آموزش، قصد داریم تا برخی از دیگر متدهای مَجیک در زبان پی‌اچ‌پی را مورد بررسی قرار دهیم اما پیش از هر چیز، داخل پوشهٔ oop پوشه‌ای تحت عنوان magic-methods ساخته و ساختار پروژه‌هایی که در آموزش‌های گذشته نوشتیم را داخل آن ایجاد می‌کنیم.

آشنایی با مَجیک متد ()set__

این مَجیک متد در مواقعی کاربرد دارد که بخواهیم پراپرتی‌های کلاس را مقداردهی کنیم. برای این منظور، کلاس User را به صورت زیر می‌سازیم:

<?php
namespace SokanAcademy;

class User
{
    public $info = [];

    public function __set($name, $value)
    {
        $this->info[$name] = $value;
    }
}

داخل بدنهٔ کلاس User یک پراپرتی از جنسِ آرایه تحت عنوان info$ ساخته‌ایم که هیچ مقدار پیش‌فرضی ندارد. سپس مَجیک متد ()set__ را نوشته و دو پارامتر ورودی برایش در نظر می‌گیریم تحت عناوین name$ و value$ که این دو پارامتر برای کارکرد صحیح این مَجیک متد الزامی هستند. سپس داخل این متد پراپرتی info$ را فراخوانی کرده و پارامتر name$ را به عنوان کلیدی جدید برای آرایهٔ مذکور در نظر گرفته و پارامتر value$ را به عنوان مقدار آن قملداد کرده‌ایم. حال فایل index.php را به صورت زیر تکمیل می‌کنیم:

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

$user = new SokanAcademy\User();
$user->fName = "Behzad";
$user->lName = "Moradi";
var_dump($user->info);

همان‌طور که می‌بینیم، آبجکتی تحت عنوان user$ از روی کلاس User ساخته سپس نام این آبجکت را نوشته و پس از درج علائم <- نامی دلخواه همچون fName در نظر گرفته و مقدار آن را برابر با یک استرینگ قرار داده‌‌ایم (به همین منوال، lName را نیز سِت کرده‌ایم.) در واقع، در مثال فوق نام‌های fName و lName به پارامتر ورودی name$ در متد ()set__ منتسب شده و به عنوان کلیدهای آرایهٔ info$ در نظر گرفته خواهند شد و استرینگ‌هایی هم که به عنوان مقادیر این دو کلید در نظر گرفته‌ شده‌اند نیز با پراپرتی value$ این متد مَچ شده و به عنوان مقادیر اِلِمان‌های آرایه در نظر گرفته خواهند شد. در نهایت هم با استفاده از دستور ()var_dump مقادیر پراپرتی info$ را چاپ کرده‌ایم به طوری که خواهیم داشت:

array(2) {
    ["fName"]=>
    string(6) "Behzad"
    ["lName"]=>
    string(6) "Moradi"
}

می‌بینیم که کلیدهای مد نظرمان با مقادیرم متناظرشان که پیش از این وجود خارجی نداشتند به درستی ایجاد شده‌اند.

آشنایی با مَجیک متد ()get__

این مَجیک متد همان‌طور که از نامش مشخص است، به منظور دریافت یک پراپرتی می‌تواند مورد استفاده قرار گیرد که برای درک بهتر سازوکار آن، کلاس User را به صورت زیر تکمیل می‌کنیم:

<?php
namespace SokanAcademy;

class User
{
    public $info = [];

    public function __set($name, $value)
    {
        $this->info[$name] = $value;
    }

    public function __get($name)
    {
        return $this->info[$name];
    }
}

مَجیک متد ()get__ یک پارامتر ورودی الزامی دارا است که در این مثال نامی همچون name$ برایش در نظر گرفته‌ایم و داخل این متد هم دستور داده‌ایم تا کلید متناظر با این پارامتر از پراپرتی info$ ریترن گردد. جهت تست این متد، فایل index.php را به صورت زیر آپدیت می‌کنیم:

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

$user = new SokanAcademy\User();
$user->fName = "Behzad";
$user->lName = "Moradi";
// var_dump($user->info);
echo $user->fName;

می‌بینیم که در خط نهم کلید مد نظرمان که fName است را به آبجکت user$ منتسب کرده‌ایم و دستور داده‌ایم تا مقدار آن چاپ گردد که با اجرای این اسکریپت، استرینگ مربوطه چاپ خواهد شد. در واقع، به محض این که مفسر پی‌اچ‌پی به دستور ;echo $user->fName برسد، مَجیک متد ()get__ به صورت خودکار فراخوانی خواهد شد.

در ارتباط با مَجیک متدهای ()set__  و ()get__ این نکته را همواره باید به خاطر داشت که این متدها صرفاً زمانی به صورت خودکار فراخوانی خواهند شد که با پراپرتی‌هایی سروکار داشته باشیم که از قبل وجود ندارند و چنانچه یک پراپرتی از قبل وجود داشته باشد، این متدها هرگز اجرا نخواهند شد. برای روشن‌تر شدن این مسئله، کلاس User را به صورت زیر تکمیل می‌کنیم:

<?php
namespace SokanAcademy;

class User
{
    public $info = [];

    public function __set($name, $value)
    {
        die ("We`re in __set()");
        // $this->info[$name] = $value;
    }
    
    public function __get($name)
    {
        return $this->info[$name];
    }
}

همان‌طور که ملاحظه می‌شود، دستور قبلی داخل متد ()set__ را کامنت کرده و در عوض از دستور ()die استفاده کرده‌ایم تا بتوانیم رفتار پی‌اچ‌پی را رصد کنیم. اکنون اگر فایل index.php را با کدهای زیر مبنا قرار دهیم:

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

$user = new SokanAcademy\User();
$user->fName = "Behzad";
$user->lName = "Moradi";

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

We`re in __set()

در واقع،‌ می‌بینیم که مَجیک متد ()set__ فراخوانی شده است چرا که قصد داریم پراپرتی‌هایی را ایجاد کنیم که از قبل وجودِ خارجی نداشته‌اند. حال کلاس User را به صورت زیر تغییر می‌دهیم:

<?php
namespace SokanAcademy;

class User
{
    public $info = [];

    public function __set($name, $value)
    {
        $this->info[$name] = $value;
    }

    public function __get($name)
    {
        die("We`re in __get()");
        // return $this->info[$name];
    }
}

می‌بینیم که این بار دستور ()die را داخل متد ()get__ نوشته‌ایم. اکنون فایل index.php را به صورت زیر آپدیت می‌کنیم:

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

$user = new SokanAcademy\User();
$user->fName = "Behzad";
$user->lName = "Moradi";
echo $user->fName;

در حقیقت، در خط هشتم قصد داریم تا مقدار پراپرتی‌ای که از قبل وجود نداشته است را فراخوانی کنیم به طوری که در خروجی خواهیم داشت:

We`re in __get()

می‌بینیم که مَجیک متد ()get__ به درستی فراخوانی شده است. در عین حال، توجه داشته باشیم که اگر یک پراپرتی از قبل داخل کلاس تعریف شده باشد و بخواهیم به آن دست یابیم، این متد هرگز اجرا نخواهد شد به طوری که مثلاً داریم:

<?php
namespace SokanAcademy;

class User
{
    public $info = [];
    public $tmpProperty = "This is temporary property";

    public function __set($name, $value)
    {
        $this->info[$name] = $value;
    }
    
    public function __get($name)
    {
        die ("We`re in __get()");
        // return $this->info[$name];
    }

}

یک پراپرتی جدید تحت عنوان tmpProperty$ با یک مقدار پیش‌فرض ساخته‌ایم. حال مجدد به فایل index.php باز می‌گردیم:

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

$user = new SokanAcademy\User();
$user->fName = "Behzad";
$user->lName = "Moradi";
echo $user->tmpProperty;

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

This is temporary property

می‌بینیم با توجه به این که پراپرتی tmpProperty$ از قبل وجود داشته است، مَجیک متد ()get__ هرگز اجرا نخواهد شد.

همچون متد ()construct__، متدهای ()set__ و ()get__ حتی اگر به صورت دستی هم کال نشوند، در صورتی که قصد کار با یک پراپرتی را داشته باشیم که وجودِ خارجی ندارد، به صورت خودکار توسط مفسر پی‌اچ‌پی کال خواهند شد که برای روشن‌تر شدن این مسئله، فایل جدیدی تحت عنوان User2.php داخل پوشهٔ classes ساخته و آن را به صورت زیر تکمیل می‌کنیم:

<?php
namespace SokanAcademy;

class User2
{

}

می‌بینیم که این کلاس حاوی کد خاصی نیست. حال به فایل index.php بازگشته و آن را به صورت زیر آپدیت می‌نماییم:

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

// $user = new SokanAcademy\User();
// $user->fName = "Behzad";
// $user->lName = "Moradi";
// echo $user->tmpProperty;

$userTwo = new SokanAcademy\User2();
$userTwo->job = "Developer";
$userTwo->programmingLanguage = "PHP";
echo $userTwo->job;
echo $userTwo->programmingLanguage;

ابتدا کدهای قبلی را کامنت کرده سپس آبجکتی تحت عنوان userTwo$ از روی کلاس User2 ساخته سپس در خطوط یازدهم و دوازدهم سعی کرده‌ایم تا دو پراپرتی جدید تحت عناوین job و programmingLanguage بسازیم و مقادیری را نیز برای آن‌ها در نظر گرفته‌ایم. در واقع، این دو خط از کد منجر به فراخوانی متد ()set__ خواهند شد زیرا پیش از این چنین پراپرتی‌هایی وجود نداشته‌اند. در ادامه، با استفاده از دستور echo قصد داریم تا مقدار این پراپرتی‌ها را نمایش دهیم و نیاز به توضیح نیست که به منظور اجرای خطوط سیزدهم و چهاردهم، متد ()get__ فراخوانی خواهد شد. 

در پایان لازم به یادآوری است که جهت آشنایی با دیگر مَجیک متدهای زبان برنامه‌نویسی پی‌اچ‌پی، می‌توانید به لینک Magic Methods در سایت رسمی زبان پی‌اچ‌‌پی مراجعه نمایید.

online-support-icon