امروز قصد دارم به یکی از ترفندهایی بپردازم که با کمک اون می تونید به راحتی یک سیستم hookable رو در php پیاده سازی کنید. دقیقا مانند اون چیزی که در وردپرس وجود داره. سیستم های hookable سیستم هایی هستند که برنامه نویس می تونه در جاهای مختلف از سورس پروژه hook های مختلف رو رجیستر کنه و هر زمان که نیاز داشت تمام hook ها رو با یک دستور فراخوانی کنه.
اگر نمی دونید یک سیستم hookable چی هست در ابتدا به طور مختصر اون رو با مثال هایی از سیستم مدیریت محتوای وردپرس براتون توضیح میدم. پس با من همراه باشید:
در وردپرس تابعی وجود داره به اسم add_action که نحوه استفاده از اون به صورت زیر هست:
add_action(‘tag_name’ , ‘function_name’);
function function_name(){
// do something
}
و یک تابع دیگه در وردپرس داریم به نام do_action که به صورت زیر استفاده میشه:
do_action(‘tag’ , $args);
در وردپرس برنامه نویس می تونه توابع add_action مختلفی رو با یک برچسب (پارامتر tag_name) بنویسه و اون ها رو در سیستم رجیستر کنه و هر زمان که خواست با یک بار فراخوانی تابع do_action تمام توابعی رو که به عنوان پارامتر دوم تابع add_action ثبت شدن، فراخوانی کنه. به عبارت دیگه وردپرس نام برچسب تابع do_action رو با برچسب های توابع add_action تطبیق میده و تمام توابع معرفی شده را صدا می زنه.
حالا ما می خوایم همین کار رو برای یک سیستم اختصاصی که بدون سیستم مدیریت محتوای وردپرس نوشته شده پیاده سازی کنیم. پس تمام نکاتی رو که گفته میشه با دقت گوش کنید و قدم به قدم با من پیش برید تا این موضوع رو کامل یاد بگیرید.
برای تعریف هوک در یک سیستم اختصاصی ما یک تابع به شکل زیر می نویسیم. این تابع هم وظیفه صدا زدن هوک ها و هم وظیفه تعریف هوک ها رو به عهده داره.
function hook($tag_name, $value = NULL, $callback = NULL) { static $events;
if($callback !== NULL) { if($callback) { $events[$tag_name][] = $callback; } else { unset($events[$tag_name]); } } elseif(isset($events[$tag_name])) // Fire a callback { foreach($events[$tag_name] as $function) { $value = call_user_func($function, $value); } return $value; } }
پارامتر اول تابع نام برچسب هست (دقیقا مثل پارامتر اول توابع add_action و do_action در وردپرس).
پارامتر دوم، مقداری هست که قصد داریم به تابعی که می خواد اجرا بشه پاس بدیم. (این مورد طبیعتا فقط به هنگام فراخوانی هوک مورد استفاده قرار می گیره و موقع تعریف هوک کاربردی نداره. بنابراین مقدار null رو بهش پاس میدیم).
و پارامتر سوم تابعی که می خوایم به به هنگام فراخوانی هوک اجرا بشه. (این مورد برعکس مورد دوم هست. یعنی فقط به هنگام تعریف هوک مورد استفاده قرار می گیره و زمانی که قصد داریم هوک رو فراخوانی کنیم مقدار null رو بهش پاس میدیم.)
در بدنه تابع یک متغیر به اسم events با کلمه کلیدی static تعریف شده. کاربرد کلمه کلیدی static برای زمانی هست که قصد داریم مقادیر ذخیره شده در متغیر events رو در فراخوانی های مجدد تابع نگه داریم و مانع از این بشیم که این مقادیر از بین برن.
در خط بعد چک شده که اگر متغیر callback برابر null بود (همون طور که توضیح دادم به این معنی هست که ما در حال تعریف یک هوک هستیم نه فراخوانی اون) باید باید دستورات زیر مجموعه اون انجام بشن.
همون طور مشخشه ما از عملگر !== استفاده کردیم به این خاطر که اگر برای مثال برای callback مقدار false پاس داده شده بود بتونیم اون رو از مقدار null تشخیص بدیم.
حالا دستورات زیر مجموعه این شرط به این صورت هستن:
در صورتی که callback خالی نبود، ما تابع callback رو به مجموعه event هایی که قصد فراخوانی اون رو داریم اضافه می کنیم. در غیر این صورت یعنی ما باید event رو حذف کنیم.
حالا در صورتی که در آرایه events برچسبی با مقدار ذخیره شده در متغیر tag_name وجود داشته باشه یعنی ما قصد داریم یک event رو فراخوانی و اجرا کنیم، که در این صورت روی تموم event های اون برچسب foreach می زنیم و یکی یکی توابع مربوط به اون ها رو اجرا می کنیم.
حالا نحوه تعریف و فراخوانی هوک ها به چه صورت هست؟ این مورد رو با یک مثال توضیح میدم
مثلا می خوایم با عضویت کاربر در سایت برای او پیامک خوش آمد گویی ارسال کنیم. برای اینکار یک hook به شکل زیر تعریف می کنیم:
hook(‘user_registered’ , null , function($userId){
// get user mobile number by user id
// send sms
});
همچنین قصد داریم به هنگام ثبت نام کاربر ایمیل اون رو به لیست خبرنامه اضافه کنیم:
hook(‘user_registered’ , null , function($userId){
// get user email by user id
// add user email to newsletter list
});
در نهایت هوک رو به شکل زیر صدا می زنیم تا همه توابع به صورت خودکار اجرا بشن:
$userId = 12345;
hook(‘user_registered’ , $userId);
و اگر بخوایم یک هوک رو حذف یا deregister کنیم به شکل زیر عمل می کنیم:
hook(‘user_registered’ , null , false);
و سخن آخر:
سیستم های hookable به شما کمک می کنند که کدهای تمیز تری داشته باشید و به راحتی یک سیستم مبتنی بر رویداد ها رو مدیریت کنید. امیدوارم این مقاله برای شما مفید بوده باشه. اگر سوال، نظر یا پیشنهادی دارید خوشحال میشم با من مطرح کنید. از طریق بخش کامنت های این مقاله با من در تماس باشید.