Quay lại

Mở rộng class behaviour trong Laravel sử dụng Macros Chuyên mục PHP và Laravel    2023-07-28    1.4k Lượt xem    39 Lượt thích    comment-3 Created with Sketch Beta. 0 Bình luận

Mở rộng class behaviour trong Laravel sử dụng Macros

Trong bài viết này, mình sẽ thảo luận về tính năng trong Laravel mà bạn có thể mở rộng chức năng của một số core classes nhất định của Laravel mà không cần vào codebase gốc để chỉnh sửa. Hay nói cách khác, thêm các phương thức vào class một cách linh hoạt.

  • Từ lóng chuyên ngành CNTT trong bài viết - behavior :Trong lập trình hướng đối tượng, hành vi (behavior) là các hàm (function) được định nghĩa trong một lớp (class).

Macroable Classes

Laravel cung cấp trait này được gọi là Illuminate\Support\Traits\Macroable với mục đích duy nhất là tạo ra lớp “Macroable” mà nó được sử dụng. Một class có thể macroable, nghĩa là nó cho phép bạn thêm các phương thức bổ sung vào lớp đó trong thời gian chạy.

Vì vậy, những gì mà trait này làm là cho phép các nhà phát triển thêm behaviour bổ sung vào lớp mà không cần sửa đổi mã nguồn gốc của lớp. Bạn đặc biệt cần kiểm tra xem class bạn có muốn thêm behaviour sử dụng đặc điểm này hay không để sử dụng macro. Dưới đây là một vài Laravel classes sử dụng Macroable trait:

  • Illuminate\Support\Collection
  • Illuminate\Support\Str
  • Illuminate\Http\UploadedFile
  • Illuminate\Http\RedirectResponse
  • Illuminate\Http\Request
  • Illuminate\Routing\ResponseFactory
  • Illuminate\Routing\UrlGenerator
  • Illuminate\Routing\Router

Khai báo Macros

Chẳng hạn, chúng ta có lớp Illuminate\Support\Collection trong Laravel, đây là lớp “macroable”. Bây giờ, để thêm một phương thức bổ sung, giả sử một phương thức bổ sung có tên makeKebab cho class này sẽ chuyển đổi từng item của collection thành kebab case (nó là kiểu slug như này nè các bạn "laravel-is-awesome"), bạn có thể sử dụng phương thức tĩnh ::macro như vậy.

namespace App\Providers;

use Illuminate\Support\Collection;
use Illuminate\Support\Str;

class AppServiceProvider
{
    public function boot()
    {
        Collection::macro('makeKebab', function () {
            return $this->map(function ($value) {
                return Str::kebab($value);
            });
        });
    }
}

Như bạn có thể thấy, thông thường bạn cần khai báo macro vào phương thức boot trong service provider’s . Trong trường hợp của chúng ta, đó là App\Providers\AppServiceProvider. Ở đây, chúng ta đã gọi phương thức ::macro trên Collection class chấp nhận hai đối số. Đối số đầu tiên là tên của phương thức mà chúng ta sẽ sử dụng và đối số thứ hai là một closure thực hiện chức năng thực tế.

Sử dụng Macros

Bây giờ chúng ta có thể gọi phương thức makeKebab() trên collection mà trong trường hợp của chúng ta sẽ chuyển đổi tất cả items của collection thành kebab case. Đây là cách sử dụng nó.

$collection = collect(['laravel is awesome', 'foo bar']);

$upper = $collection->makeKebab();

// ['laravel-is-awesome', 'foo-bar']

OK rồi! Đó là cách bạn có thể thêm behaviour vào class mà không làm ảnh hưởng đến việc triển khai ban đầu của lớp.

Cách thức hoạt động

Nếu bạn xem Illuminate\Support\Traits\Macroable trait, bạn sẽ biết nó bằng cách sử dụng trait này, lớp của bạn sẽ kế thừa thuộc tính mảng $macro static. Và bằng cách sử dụng phương thức macro tĩnh, nó sẽ chỉ định closure là có thể callable cho $name làm chỉ mục của $macro như vậy.

public static function macro($name, $macro)
{
    static::$macros[$name] = $macro;
}

Bây giờ, khi phương thức được gọi trên lớp đó, giả sử makeKebab trong ví dụ trước của chúng ta, vì phương thức này không thể truy cập được trong lớp, nên nó sẽ trigger magic method __call()  của PHP. Đây là phiên bản của magic method  __call() trong Macroable trait.

public function __call($method, $parameters)
{
    if (! static::hasMacro($method)) {
        throw new BadMethodCallException(sprintf(
            'Method %s::%s does not exist.', static::class, $method
        ));
    }

    $macro = static::$macros[$method];
    if ($macro instanceof Closure) {
        return call_user_func_array($macro->bindTo($this, static::class), $parameters);
    }
    
    return $macro(...$parameters);
}

Điều xảy ra ở đây là, trước tiên, nó sẽ kiểm tra xem phương thức đã chỉ định có tồn tại trong thuộc tính $macro hay không. Nếu không, nó sẽ ném ra BadMethodCallException và nếu nó tồn tại, nó sẽ tiến hành gọi Closure (là tham số được cung cấp dưới dạng tham số thứ hai của phương thức ::macro) bằng cách sử dụng phương thức call_user_func_array cùng với các tham số đã chỉ định.

Kết thúc

Laravel Macro rất tuyệt nếu bạn muốn nhanh chóng tạo ra repeating logic trong Laravel’s dựa trên các core classes của Laravel bất cứ khi nào bạn thấy mình rơi vào tình thế tiến thoái lưỡng nan khi sử dụng lại mã của mình.

Bình luận (0)

Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough

Bài viết liên quan

Learning English Everyday