بایگانی ماهیانه: دی ۱۳۹۹

ماکرو ها در لاراول macro in laravel

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

در فایل AppServiceProvider در متد بوت کد زیر را مینویسیم.

    public function boot()
    {
        Response::macro('hi', function ($name) {
            return 'Hi ' . $name ;
        });
    }

و الان می میتوانیم متد تعریف شده را روی کلای Response صدا بزنیم.
در فایل web کد زیر را مینویسیم .

use Illuminate\Support\Facades\Response;
Route::get('macro', function () {
    echo Response::hi('Ali');
    echo ' ';
    echo response()->hi('Ali');
});

خروجی

//localhost:8000/macro
Hi Ali Hi Ali

مثال های بیشتر از راهنمای لاراول
https://laravel.com/docs/8.x/collections#extending-collections
https://laravel.com/docs/8.x/responses#response-macros
https://laravel.com/docs/8.x/scout#builder-macros
سوال پیش میاد چه نیازی هست به این کار؟
پاسخی که من به ذهنم میرسه، اگه یه کار تکراری رو توی یه کلاس انجام میدیم میتونیم اون رو یک بار به عنوان ماکرو به کلاس اضافه کنیم و بعدا بارها از اون استفاده کنیم، و کمک میکنه کد کمتر بنویسیم و کد کمتر هم یعنی باگ کمتر. اگه از ماکرو استفاده نکنیم از چی می‌تونیم استفاده کنیم؟
از ارث بری :
از تریت ها :
از متدهای کمکی(helpers) :
همه اینها کمک میکنن کد کمتر بنویسیم اما خوبی ماکرو اینه که میتونیم رفتار کلاس های موجود رو در زمان اجرا runtime تغییر بدیم.
آیا میتوانیم همه کلاسها را تغییر دهیم ؟‌
خیر، فقط کلاسهایی که Macroable هستند.

با جستجوی Macroable در کد لاراول کلاس های پیش فرض که در لاراول به صورت ماکروابیل تعریف شده اند،‌را میتوانید مشاهده کنید.  (یک لیست هم اینجا هست)

یک کلاس ماکروابیل تعریف کنیم.

<?php

namespace App\Services;

use \Illuminate\Support\Traits\Macroable;

class Person {
    use Macroable;

    private $name;

    public function __construct($name) 
    {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

و در متد بوت پروایدر یک ماکرو ساده تعریف میکنیم.

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        \App\Services\Person::macro('hi', function() {
            return 'Hi ' . $this->getName();
        });
    }
}

و آن متد را روی کلاس اجرا میکنیم.

// http://localhost:8000/person
Route::get('person', function () {
    $person = new \App\Services\Person('Ali');
    echo $person->hi(); // use macro
    // Hi Ali
});

می بینیم که به راحتی میتوانیم کلاس ها را ماکروابل تعریف کنیم و آنها را گسترش دهیم. با نگاهی به تریت ماکروابیل،  میبینیم که از reflection ها استفاده میکند.

میتوانیم برای خودمان متد های پرکاربرد را ذخیره کنیم و دفعه بعد به صورت ماکرو آنها را تعریف کنیم. 🙂
البته حواسمون هست که ماکرو رو میتونیم در سرویس پروایدرهای دیگری غیر از AppServiceProvider تعریف کنیم، و اسم های خوانا تری هم برای آنها انتخاب کنیم.
یک پکیج نمونه که قابلیت های لاراول رو با ماکرو ها توسعه داده
https://github.com/spatie/macroable

فایل ها