ماکرو (Macro) یکی از ویژگیهای قدرتمند فریمورک لاراول هست که انعطافپذیری بیشتری برای گسترش کلاسهای درونی به شما میده. ماکروهای لاراول به شما این امکان رو میدن که قابلیتهای سفارشی خودتون رو به اجزای داخلی لاراول اضافه کنید. در ادامه و در این آموزش نحوه کار با این خاصیت رو بررسی خواهیم کرد.
همانطور که گفتیم شما با این خاصیت میتونید قابلیتهای خودتون رو به کلاسهای داخلی لاراول اضافه کنید. منتهی پیش از اون باید مطمئن باشید که اون کلاس خاصیت ماکرو رو داره یا اصطلاحا Macroable هست. برای این منظور کافیه اون کلاس مدنظرتون رو نگاه کنید و ببینید که آیا این قابلیت در کلاس وجود داره یا نه:
use Macroable;
در زیر میتونید لیستی از کلاسها در لاراول که خاصیت ماکرو دارند و شما میتوانید قابلیتهای خودتون رو به اونها اضافه کنید لیست شدند:
در ادامه نحوه افزودن چند قابلیت به کلاس Illuminate\Support\Str و سفارشی کردن این کلاس رو آموزش خواهم داد. برای این منظور من ابتدا یک پروژه خام لاراول رو نصب کردم. اجازه بدید پیش از شروع کلاس Str رو باهم یک نگاه بکنیم همانطور که مشاهده میکنید این کلاس خاصیت Macroable رو داره:
خاصیت Macroable در کلاس Str
خاصیت Macroable هم یکسری متدهایی رو داره که امکان تعریف قابلیتهای جدید رو هر کلاسی مهیا میکنه! در مورد خاصیت و trait همانطور که پیشتر هم گفتیم میتونید صفاتی رو که برای یک هدف معین لازم دارید در قالب یک trait چندین بار مورد استفاده قرار دهید.
بیایید کمی عمیقتر به این trait نگاهی بیاندازیم. اگر وارد مسیر Illuminate\Support\Traits\Macroable بشوید در این خاصیت دو تابع به نام macro و mixin وجود دارند که هر دو برای تعریف قابلیت جدید شما استفاده میشه. در macro شما دو آرگومان دارید که یکی نام قابلیت جدید و دیگری یک متد calback هست که در واقع میتونید اینجا اون قابلیت مورد نظرتون رو وارد میکنید و تابع بعدی mixin هم همانطور که از توضیحاتش مشخصه امکان افزودن کلاسی که قابلیت جدید رو باهاش تعریف میکنید میده. بنظرتون این نوع تعریف آشنا نیست!!!!
اگر آموزشارو دنبال کرده باشید ما پیشتر چیزی شبیه به این نوع تعریف رو در View Composer مشاهده کردیم مقاله اون هم در زیر قرار دادم میتونید مطالعه کنید:
اما تابع دیگری که بیشتر میخوام به اون توجه کنید تابع callStatic__ هست در مورد نحوه عملکرد این تابع جالب که جزو خاصیتهای خود PHP هست هم بطور کامل در آموزش Facade بررسی کردیم که مقاله اون هم در زیر قرار دادم:
خواهید دید که در ابتدا بررسی میشه که آیا تابع مورد نظر قبلا تعریف شده یا نه! یعنی اگر تابع سفارشی ما در آرایه macro$ وجود داشته آن رو به ما برمیگردونه درغیر اینصورت خطای تعریف نشدن تابع در کلاس رو دریافت خواهیم کرد.
در ادامه اگر تابع ما از نوع Closure باشه scope اون رو به کلاس مد نظر ما متصل میکنه. دقت کنید که در اینجا static::class به کلاسی که خاصیت ماکرو داره اشاره میکنه.
در نهایت هم ورودیهایی که در نظر گرفتیم رو به این تابع میده و خروجی تابع رو به ما برمیگردونه!
این کلاس برای نمایش نوع توابع بینام (Anonymous functions) استفاده میشه! بنابراین توابع بینام از نوع Closure هستند. داخل فریمورک لاراول از این توابع بسیار استفاده شده، شما پیش از این با این نوع توابع کار کردید برای مثال داخل Routeها:
Route::get('/macro', function () {
dd(Str::currency('10000000') );
});
یکی از مشخصههای این توابع استفاده از use هست که امکان دسترسی به متغیرهای خارج از تابع رو هم میده! از طرفی هم عموما برای صدا زدن این توابع یکبار آنها را به یک متغیر پاس میدن و بعد اون متغیر رو صدا میزنن:
$greeting = function () {
return "Hello world";
}
$greeting();
اما همانطور که در خاصیت Macroable هم مشاهده کردید Closureها قابلیتهای دیگری هم دارند که یکی از آنها bindTo هست، به مثال زیر توجه کنید:
<?php
$myClosure = function() {
echo $this->property;
};
class MyClass
{
public $property = 'Hello world!';
}
$myInstance = new MyClass();
$myBoundClosure = $myClosure->bindTo($myInstance);
$myBoundClosure();
>> "Hello world!"
همانطور که در داک php هم مشاهده میکنید اولین آرگومان این تابع به یک شی اشاره میکنه و به موجب اون کلمه کلیدی که داخل تابع بینام تعریف شده معنی پیدا میکنه. همچنین در مثال فوق اگر متغیر از نوع protected یا private میبود آنوقت تابع بینام ما دسترسی نمیداشت و شما خطای عدم دسترسی به متغیر رو دریافت میکردید. در اینصورت پای آرگومان دوم این تابع میاد وسط که با تعریف کلاس در آنجا فضای کاری یا scope تابع رو هم در کلاس تعریف میکردید:
من برای اینکه متوجه تاثیر این تابع در کار خودمون بشیم به خاصیت Macroable رفتم و خطی که مربوط به bind کردن رو تست کردم. همانطور که مشاهده میکنید اگر این خط حذف بشه تابع بینام ما به کلاس MyStrMixins اشاره میکنه:
در حالیکه ما میخواستیم کلاس Str رو توسعه بدیم بنابراین توابع جدید باید محدود به کلاس Str باشند. در نتیجه تاثیر عملکرد bindTo بصورت زیر باعث میشه تا توابع جدید به کلاس مورد نظر ارجاع داد بشن:
خب حالا بیایید به AppServiceProvider برگردیم و در متد boot یک تابع سفارشی به کلاس Str اضافه کنیم برای اینکار همانطور که گفتیم دو متد وجود داره. اجازه بدید ابتدا با متد macro اینکارو انجام بدیم:
همانطور که مشاهده میکنید من در اینجا یک تابع با نام currency به کلاس Str اضافه کردم که با کمک regex نمایش پولی ایجاد میکنه:
Str::currency('10000000');
>> "10,000,000"
به همین راحتی ما کلاس Str از لاراول رو گسترش دادیم. به همین صورت میتونید برای کلاسهای دیگری که Macroable هستند و لیست آنها رو در بالا آوردیم این کار رو انجام بدید. اما اگر توابع ما زیاد باشند وارد کردن همه اینها اینجا مناسب نیست لذا میتوان از تابع دیگر mixin که به آن اشاره شد استفاده کنیم. برای این منظور ابتدا کلاسی بصورت زیر تعریف میکنیم:
همانطور که گفته شد از آنجایی که در خاصیت Macro هر تابع بصورت بینام هست بنابراین در این کلاس ما یک تابع رو بازمیگردونیم. ضمنا توجه کنید که اگر بخواهیم آرگومانهای دیگری هم تعریف کنیم داخل تابع بینام این کار انجام میشه!
در ادامه کافیه که به متد boot در AppServiceProvider برگردیم و با کمک mixin کلاس Str رو با توابع خودمون شخصیسازی کنیم:
حالا اگر بار دیگه توابع خودمون رو صدا بزنید میبینیم که به درستی کار خواهند کرد:
خب تبریک میگم شما در این آموزش یاد گرفتید که چطور میشه کلاسهای درونی لاراول رو هم تغییر بدید و برای کار خودتون اون رو شخصیسازی کنید. یکی از کاربردهای این ابزار که خود من معمولا از اون استفاده میکنم بخش response است که میتونید خروجیهارو متناسب با نیازتون ویرایش کنید.
امیدوارم از این آموزش هم لذت برده باشید!
کدهای مربوط به این آموزش در گیتهاب رو میتونید از اینجا مشاهده کنید: