متدهای جادویی در PHP

اسفند ۸, ۱۳۹۰ توسط : سعید

متدهای جادویی در PHP

PHP شامل تعدادی از متدهاییست که با نام ” متدهای جادویی ” شناخته میشن.این متدها با دو زیر خط (Underline یا underscore) شروع میشن.این متدها در جاهای مختلف استفاده میشن و خیلی مفید هستن.در ادامه نگاهی میکنیم به متهای جدویی در PHP .

متد سازنده کلاس یا __construct()

اگر با برنامه نویسی شیء گرا در PHP آشنا باشید حتمن با این متد کار کردید.این متد هنگامی که یک نمونه از یک کلاس ساخته میشه اجرا خواهد شد.مثال زیر رو در نظر بگیرید :


class Animal{

function __construct()

{

echo 'Animal';

}

}

$animal = new Animal();

// output : Animal 

در کلاس Animal یک متد ایجاد کردیم با نام __construct() و در این متد رشته Animal رو نمایش دادیم. هنگامی که از کلاس Animal یک نمونه ایجاد میکنیم تابع __construct() اجرا میشه و رشته Animal در خروجی نمایش داده میشه.

متد مخرب یا __destruct()

این متد برعکی متد __construct عمل میکنه.یعنی هنگامی که کلاس میخواد از حافظه خارج بشه این متد اجرا میشه.

مثال :


class DB{

…..

function __destruct()

{

$db->disconnect();

}

…..

}

$db = new DB();

unset($db); 

در کلاس بالا هنگامی که تابع unset میخواد کلاس $animal رو از حافظه خارج کنه متد __destruct() اجرا میشه و ارتباط با دیتابیس قطع میشه.

Overloading در PHP

در PHP واژه Overloading به معنی ایجاد متدها و متغیرهای داینامیک است. این متدها و متغیر ها به وسیله متدهای جادویی یا Magic Methods ساخته میشن.

ساخت متغیرهای داینامیک در PHP

متد __set

این متد برای ایجاد متغیرهای داینامیک استفاده میشه.متغیرهایی که یا داخل کلاس وجود ندارن یا متغیرهایی که در خارج از کلاس بهشون دسترسی نداریم.

مثال :


class Car

{

private $vars = array() ;

function __set($name , $value)

{

$this->vars[$name] = $value ;

}

}

$car = new Car();

$car->wheel = 4 ;

$car ->color = 'red';

$car->name = 'BMW'; 

برای داشتن متغیرهای داینامیک بهترین راه استفاده از آرایه هاست. در کلاس Car یک آرایه با نام $vars ایجاد کردیم . دسترسی به آرایه $var به صورت Private تعریف شده یعنی در بیرون از کلاس به این آرایه دسترسی نداریم.سپس با متد __set متغیر $var رو مقدار دهی میکنیم.متد __set دو پارامتر میگیره.اولی نام کلید (key) و دومی مقدار (value) .

هنگامی که شما از کد زیر استفاده میکنید :


$car->color = 'red'; 

در حقیقت دارین ار زیر رو انجام میدید :


$car->vars['color'] = 'red'; 

همینطور که میبینید استفاده از متد __set خیلی میتونه در کار با کلاسها به ما کمک کنه.

متد __get()

هنگامی که از متد __set برای ایجاد متغیرهای داینامیک در کلاس استفاده میکنیم نیاز داریم که بتونیم به این متغیرهای داینامیک دسترسی داشته باشیم و از مقادیر این متغیرها استفاده کنیم.با استفاده از متد __get به راحتی میتونیم این ار رو انجام بدیم.


class Car

{

private $vars = array() ;

function __set($name , $value)

{

$this->vars[$name] = $value ;

}

function __get($name)

{

return $this->vars[$name];

}

}

$car = new Car();

//set values

$car->wheel = 4 ;

$car ->color = 'red';

$car->name = 'BMW';

// Get values

echo $car->color ; 

متد __get یک پارامتر میگیره که این پارامتر در اصل نام متغیرمونه. هنگامی که از کد :


echo $car->color ; 

استفاده میکنیم در حقیقت کد زیر در پشت صحنه اتفاق میافته :


echo $car->vars['color'] ; 

ساخت متدهای داینامیک در PHP

در قسمت قبل دیدید که چطوری میتونیم در PHP متغیرهای داینامیک بسازیم و یاد گرفتیم که چطوری از مقادیرشون استفاده کنیم.در این قسمت خواهیم فهمید چطوری میتونیم متد ها یا توابع داینامیک رو با استفاده از متدهای جادویی در PHP پیاده سازی کنیم .

   __call متد جادویی

با استفاده از متد __call میتونیم توابعی به صورت داینامیک بسازیم.این تابع دو مقدار میگیره اولی نام متد و دومی پارامترهای تابع مورد نظر رو میگیره. برای درک بهتر به مثال زیر دقت کنید :

مثال : فرض کنید شما یک کلاس برای کار با دیتابیس نوشتید.خیلی خوبه که در کلاس شما توابعی باشه تا به صورت مستقیم با فیلدهای جدول شما در ارتباط باشه.مثلا هنگامی که میخواید با استفاده از فیلد ID درون دیتابیس جستجو کنید تابعی داشته باشید به صورت findByID یا اگر جستوجوی شما بر اساس فیلد name باشه با تابع findByName بتونید دستور SQL مورد نظر رو اجرا کنید.برای این کار دوراه دارید.

اول اینکه به ازای هر فیلد جدولتون یک تابع بسازید مثلا :


class Database

{

…

function findByID($id)

{

$sql = " SELECT * FROM users WHERE id = $id";

return $this->db->query($sql);

}

function findByName($name)

{

$sql = "SELECT * FROM users WHERE name = $name";

return $this->db->query($sql);

}

}

فرض کنید تعداد فیلدهای جدول شما زیاد باشه. استفاده از این روش کار منطقی نیست.

حالا ببینیم روش دوم برای این کار چیه.

روش دوم استفاده از متد جادویی __call


class Database

{

function __call($method , $args)

{

$field =strtolower( substr($method , 6 , strlen($methods) – ۶)) ;

$sql = "SELECT * FROM $this->table WHERE $field = $args[0] " ;

return $this->db->query($sql);

}

}

$db = new Database();

$db->findByID(10);

$db->findByName('saeed');

حالا ببینیم متد جادویی __call چه کاری انجام میده که میتونیم متدهای داینامیک بسازیم.

همینطور که در بالا گفتم این متد دو پارامتر میگیره.اولی نام تارع و دومی آرایه ای از پارامترهایی که باید به تابع داینامیک پاس بشن.مثال بالا یک مثال کاملا عملی برای استفاده از متد __call بود که در خیلی جاها کاربرد داره.


$field =strtolower( substr($method , 6 , strlen($methods) – ۶)) ; 

در خط بالا ابتدا از متغیر $method قسمت findBy رو حذف کردیم.رشته ای که باقی میمونه نام فیلد جدولمونه.سپس به حروف کوچک تبدیلش کردیم و داخل دستور SQL ازش استفاده کردیم.

با این کار به تعداد فیلدهای جدول راه هست برای جستو توی دیتابیس!!

متد جادویی __callStatic

این تابع از PHP نسخه ۵٫۳ معرفی شد. دقیقا مثل __call استفاده میشه اما همینطور که از نامش مشخصه برای متدهای static کاربرد داره.

گاهی اوقات ممکنه لازم داشته باشیم یک شیء رو به یک رشته تبدیل کنیم.اگر بخواید با دستور echo یک شیء رو در خورجی چاپ کنید یک خطا اتفاق میافته :


$car = new Car();

echo $car;

// fatal error: Object of class Car could not be converted to string

متد __toString()

این زمانی اجرا میشه که بخوایم یک شیء رو در خروجی نمایش بدیم.


class Car

{

function __toString()

{

return get_class();

}

}

$car = new Car();

echo $car ; // Car

اگر داخل کلاس متد __toString() رو پیاده سازی کرده باشیم هنگامی که با دستور echo شیء $car رو میخوایم توی خروجی نمایش بدیم با خطا مواجه نمیشیم.در مثال بالا هنگامی که دستور echo $car; اجرا میشه تابع get_class() اجرا میشه.

باد آوری : تابع get_class() نام کلاس جاری رو بر میگردونه.

Serialization

Serialization به تبدیل یک شیء یا یک آرایه به رشته گفته میشه.از Serialization برای نگهداری اشاء در فایل یا دیتابیس استفاده میشه.هنگامی یک شیء رو به حالت اول برگردونیم Unserialize گفته میشه.هنگامی یک کلاس رو serialize میکنیم تمام متغیرها و اعضای کلاس ذخیره خواهند شد.اما مشکلی که هست اینه که ممکنه نخواسته باشیم مثلا متغیری که کانکشن دیتابیس رو تگهداری میکنه هم ذخیره یشه.برای این کار از متد __sleep() استفاده میکنیم.

متد جادویی __sleep()

این متد هنگامی اجرا میشه که تابعserialize() رو بخوایم روی شیء اجرا کنیم.داخل این متد میتونیم مشخص کنیم که چه متغیرهایی از کلاس اجازه دارن serialize بشن.این متد باید یک آرایه رو برگردونه.

مثال :


class My

{

public $a;

public $b;

function __construct(){

$this->b = 'salam';

$this->a = 'a';

}

function __sleep()

{

//return get_object_vars($this);

return array('b');

}

}

$m = new My();

$a = (serialize($m));

var_dump(unserialize($a));

/*خروجی :

object(My)#2 (2) { ["a"]=> NULL ["b"]=> string(5) "salam" }

*/

همینطور که میبینید در خروجی کد بالا فقط متغیر $b دارای مقدار هست.این به این خاطره که آرایه ای که در متد __sleep() برگردانده شده فقط شامل متغیر b هست.


return array('b'); 

این هط میگه که هنگام serialize کلاس My فقط متغیر b حق ذخیره شدن رو داره.

متد __wakeup()

این متد هنگامی اجرا میشه که تابع unserialize() اجرا میشه.به عنوان مثال اگر هنگام serizalize یک شیء اتصال به دیتابیس رو بسته باشید داخل متد __wakeup میتونید این اتصال رو دوباره برقرار کنید.


class Database {

//...

public function __wakeup() {

// reconnect to the network

$this->connect();

}

//...

}

متد __invoke()

این متد هنگامی اجرا میشه که بخواید از یک شیء به عنوان یک تابع استفاده کنید.


<!--?php class My { public function __invoke($x) { echo '__invoke method. $x = '.$x; } } $obj = new My(); $obj(5); //var_dump(is_callable($obj)); true ?--> 

خروجی بالا به شکل زیره :


__invoke method. $x = 5

متد جادویی __autoload()

متدهایی که در قسمت قبل آموزشش رو مشاهده کردید همگی در کلاسها قابل استفاده بودن. تابع __autoload یک تابع مستقل محسوب میشه.این تابع برای لود مستقیم کلاسها به کار میره.هنگامی که میخواید از یک کلاس یک شیء ایجاد کنید ابتدا نیاز هست که با دستور include یا require کلاس مورد نظر رو لود کنیم.


require 'classes/database.class.php';

$db = new Database();

با استفاده از تابع __autoload از require کردن های زیاد راحت میشیم.

در مثال بالا تمام کلاسهای پروژه ما در پوشه classes نگهداری میشن.


function __autoload($classname)

{

$class = 'classes/'.strtolower($classname).'.class.php';

require $class;

} 

با استفاده از تابع بالا در هر جای پروژه میتونیم به صورت خودکار کلاسها رو لود کنیم.


$db = new Database();

حرف آخر

متدهای جادویی در PHP خیلی مفید هستن و انعطاف زیادی به برنامه نویسی شیء گرا میدن.با استفاده از این متدها لذت برنامه نویسی شیء گرا دوچندان میشه.

اگر دقت کرده باشید در مقاله بالا سعی کردم ازاصطلاحات ساده برای دوستانی که اول راه هستند و با برنامه نویسی شیء گرا آشنایی زیادی ندارن استفاده کنم.مثلا یک جا از کلمه “متد (Method) ” و جای دیگه از کلمه ” تابع (function) ” استفاده کردم.منظورم از این کار این بوده که به کسانی که اول راه شیء گرایی هستن بفهمونم این ها فقط “اصطلاح” ـه و ممکنه در جاهای مختلف نامهای مختلفی داشته باشه.هنگامی که یک تابع در یک کلاس قرار میگیره به اصلاح بهش میگن ” متد ” اما مهم نیست بهش چی میگن مهم اینه که “تابع” همون “متد” ـه.

مهم درک مفهوم شیء گرایی هست و لطفا ذهن خودتون رو درگیر این اصطلاحات نکنید.

 

دانلود به صورت PDF ” متدهای جادویی در PHP”

بازدید : ۱۴۱۶۷

سعید م
اسفند ۸, ۱۳۹۰ @ ۳:۱۳ ب.ظ

ایول آق سعید. خسته نباشی. خیلی خوب بود 😉

پاسخ دادن
    سعید
    اسفند ۲۳, ۱۳۹۰ @ ۵:۱۵ ق.ظ

    ممنون سعید جان

    پاسخ دادن
علیرضا
اسفند ۱۲, ۱۳۹۰ @ ۷:۴۴ ق.ظ

عالی بود سعید. مرسی. با بخش متد های داینامیکش خیلی حال کردم. autoload هم خیلی خوب معرفی کردی. مثالت واضح و روشن بود. تنکس

پاسخ دادن
    سعید
    اسفند ۲۳, ۱۳۹۰ @ ۵:۱۴ ق.ظ

    خواهش میکنم.

    پاسخ دادن
پوریا
اردیبهشت ۱۷, ۱۳۹۱ @ ۸:۰۱ ب.ظ

مفید بود. مرسی

پاسخ دادن
محمد لطفی
شهریور ۱۹, ۱۳۹۱ @ ۵:۲۴ ق.ظ

خیلی مفید بود، ممنون…

پاسخ دادن
حسن
آبان ۷, ۱۳۹۱ @ ۱۱:۱۶ ق.ظ

سلام یه سوال در مورد متد autoload اینکه در تمام صفحات وب که داریم باید این تابع را کپی کنیم یا فقط یک با کافی است
با تشکر

پاسخ دادن
    سعید
    آبان ۷, ۱۳۹۱ @ ۱۱:۵۵ ب.ظ

    سلام
    برای استفاده باید توی همه صفحات باشه.بهتره که همه درخواست هارو به فایل index.php ارسال کنید و از اون فایل بقیه صفحات رو صدا بزنید.داخل فایل index.php توابع مربوط رو بنویسید یا include کنید که نیاز نباشه توی همه صفحات include بشن.

    پاسخ دادن
علی
دی ۷, ۱۳۹۱ @ ۵:۵۴ ق.ظ

بسیار عالی بود . از وقتی که برای ساخت مقاله گذاشتید تشکر میکنم

پاسخ دادن
محمد
اسفند ۹, ۱۳۹۱ @ ۱۲:۵۴ ب.ظ

با سپاس فراوان – عالی بود

پاسخ دادن
امین
اسفند ۲۳, ۱۳۹۱ @ ۲:۱۱ ب.ظ

سلام
سعید جان از بابت سایت خوبت تشکر میکنم

اگه ممکنه لطفا چند تا کتاب نامبر وان در زمینه آموزش php و شی گرایی و css معرفی کن
فارسی یا انگلیسی بودن کتابها مهم نیست

ممنونم

پاسخ دادن
    سعید
    اسفند ۲۴, ۱۳۹۱ @ ۳:۰۴ ب.ظ

    سلام
    خواهش میکنم
    این کتابها رو من در مورد PHP خوندم خیلی خوب بودن :
    PHP Objects, Patterns and Practice 3rd Edition
    Object-Oriented Programming with PHP5
    کتاب ” ۹۷ چیزی که باید هر برنامه نویس بداند” رو هم بخون خیلی جالبه.
    ۹۷ Things Every Programmer Should Know

    برای سی اس اس کتابی نخوندم.ولی فکر میکنم سایت sitepoint و tutsplus کتابای خوبی در این زمینه دارن.

    موفق باشی

    پاسخ دادن
مهر ۲۹, ۱۳۹۲ @ ۸:۰۵ ب.ظ

واقعا عالی و راحت توضوح دادی
خیلی ممون دوست عزیز

پاسخ دادن
فروردین ۲۹, ۱۳۹۳ @ ۱:۲۰ ق.ظ

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

    public function __construct($db)
    {
        //Is valid resource?
		
        if (!is_resource($db) || get_resource_type($db) !== 'mysql link')
            throw new Exception('This is not valid MySQL connection resource.');

        $this-&gt;_con = $db;
    }
پاسخ دادن
    سعید
    فروردین ۲۹, ۱۳۹۳ @ ۹:۰۶ ق.ظ

    این متد درواقع متد سازنده ی یک کلاس هست که یک پارامتر به نام $db میگیره و چک میکنه که آیا این پارامتر از نوع اتصال به دیتابیس هست یا خیر.

    پاسخ دادن
احسان
خرداد ۷, ۱۳۹۳ @ ۴:۵۰ ب.ظ

سلام
توی متد __call تو این قسمت خطای سینتکس هست چون اون منفی ۶ رو به فارسی نوشتی.به انگلیسی نوشتم خطا رفع شد.
$field =strtolower( substr($method , 6 , (strlen($methods)-6)));
راستی جریان این $this->table چیه؟ باید بجاش نام جدول رو بزاریم یا به چیزی اشاره می کنه داداش؟

پاسخ دادن
رضا
تیر ۱۶, ۱۳۹۳ @ ۸:۴۸ ب.ظ

عالی بود ممنون

پاسخ دادن
رضا
بهمن ۴, ۱۳۹۳ @ ۷:۱۸ ب.ظ

عالی ، تشکر

پاسخ دادن
بهمن ۱۳, ۱۳۹۴ @ ۹:۵۷ ق.ظ

ممنون … عالی بود
اما متد __autoload دیگه زیاد کاربردی نداره … با وارد شدن name space دیگه نمیشه ازش استفاده کرد 🙂

پاسخ دادن
shirin
اردیبهشت ۷, ۱۳۹۵ @ ۸:۲۸ ق.ظ

عالی بود ممنون

پاسخ دادن
mortaza7khat
مرداد ۲۳, ۱۳۹۵ @ ۱۱:۴۶ ق.ظ

محشری! خیلی آموزش کاملی بود! فک کنم تو وب فارسی تا حالا چنین مقاله کاملی ندیده بودم!

پاسخ دادن

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *


*