0

Str::is() trong Laravel: Khi Regex là quá mức cần thiết cho một dấu "Sao" (*)

Chào anh em Viblo, lại là mình đây!

Trong quá trình làm backend với hệ sinh thái Laravel, đặc biệt là khi phải cày cuốc với các hệ thống phân tích log giao dịch phức tạp hay xử lý đối soát hàng loạt mã đơn hàng, anh em chắc chắn sẽ đụng tới bài toán: Kiểm tra xem một chuỗi có khớp với một định dạng cụ thể hay không.

Phản xạ đầu tiên của những anh em "tay to" thường là lôi Regular Expression (Regex) ra để dùng (preg_match). Nhưng thực sự thì Regex giống như việc bạn vác một cây súng tỉa đi bắn ruồi vậy: Nó quá phức tạp, khó đọc và khó maintain.

Để giải quyết những bài toán so sánh chuỗi có tính khuôn mẫu đơn giản, Laravel cung cấp một helper function cực kỳ thanh lịch: str_is() (từ Laravel 6.x trở đi đã được chuyển thành class method Str::is()). Hôm nay, chúng ta cùng mổ xẻ xem nó hay ho ở điểm nào nhé!

1. Str::is() thực chất làm gì?

Hiểu một cách đơn giản nhất, Str::is() giúp bạn so sánh một chuỗi với một chuỗi mẫu (pattern) có chứa dấu sao (*).

Dấu * ở đây đóng vai trò là một Wildcard (ký tự đại diện) – nghĩa là "bất kỳ ký tự nào, độ dài bao nhiêu cũng được".

Cú pháp:

use Illuminate\Support\Str;

Str::is($pattern, $value);

Ví dụ cơ bản:

// Trả về true vì chuỗi bắt đầu bằng 'api/'
Str::is('api/*', 'api/users/1'); 

// Trả về true vì chuỗi kết thúc bằng '@gmail.com'
Str::is('*@gmail.com', 'hieu.nguyen@gmail.com'); 

// Trả về true vì chữ 'test' nằm ở giữa
Str::is('*test*', 'my_test_database'); 

2. Ứng dụng thực tế: Tại sao nó lại "ăn tiền"?

Trong các hệ thống thực tế đòi hỏi việc phân loại dữ liệu dựa trên các tiền tố (prefix) hoặc hậu tố (suffix), Str::is() tỏa sáng nhờ tính dễ đọc (Readability) tuyệt đối của nó.

Bài toán 1: Lọc log giao dịch (Transaction Logs)

Giả sử bạn đang xử lý một luồng dữ liệu quẹt thẻ từ hệ thống thiết bị nhà ga, và bạn chỉ muốn bắt các log liên quan đến các cổng ra vào bị lỗi (ví dụ mã lỗi bắt đầu bằng ERR_GATE_). Thay vì viết Regex: preg_match('/^ERR_GATE_.*$/', $errorCode), bạn chỉ cần:

if (Str::is('ERR_GATE_*', $errorCode)) {
    // Xử lý logic cảnh báo
}

Code đọc lên như ngôn ngữ tự nhiên, một bạn junior mới vào team nhìn qua cũng hiểu ngay luồng nghiệp vụ.

Bài toán 2: Phân quyền theo HTTP Request

Thực ra anh em đã dùng hàm này rất nhiều lần mà không hề nhận ra. Khi anh em viết Middleware trong Laravel để chặn các route, chúng ta hay viết:

if ($request->is('admin/*')) {
    // Check quyền admin
}

Bên dưới lớp vỏ bọc, method $request->is() chính là đang gọi thẳng vào lõi của Str::is() để đối chiếu cái URL hiện tại với chuỗi mẫu admin/*.

Bài toán 3: Kiểm tra nhiều Pattern cùng lúc

Từ các phiên bản Laravel mới, tham số $pattern của Str::is() còn cho phép nhận vào một Mảng (Array). Nếu chuỗi $value khớp với BẤT KỲ pattern nào trong mảng, nó sẽ trả về true.

$orderCode = 'ORD_2026_998877';

// Kiểm tra xem mã đơn hàng có thuộc năm 2025 hoặc 2026 không
if (Str::is(['ORD_2025_*', 'ORD_2026_*'], $orderCode)) {
    echo "Đơn hàng thuộc chu kỳ kiểm toán hiện tại!";
}

3. Đọc mã nguồn: Ma thuật đằng sau dấu *

Một người kỹ sư Backend tốt không chỉ biết dùng tool, mà còn phải hiểu công cụ đó hoạt động thế nào. Hãy cùng ngó vào "ruột" của Str::is() trong core Laravel:

public static function is($pattern, $value){
    // ... logic xử lý array pattern
    
    if ($pattern == $value) {
        return true;
    }

    $pattern = preg_quote($pattern, '#');

    // Chuyển đổi dấu * thành .* của Regex
    $pattern = str_replace('\*', '.*', $pattern);

    return (bool) preg_match('#^'.$pattern.'\z#u', $value);
}

Hóa ra, anh chàng Taylor Otwell vẫn dùng Regex! Nhưng anh ấy đã làm một việc cực kỳ tinh tế:

  • Dùng preg_quote để vô hiệu hóa tất cả các ký tự đặc biệt có trong $pattern (như dấu ?, +, [), đảm bảo chúng chỉ được coi là text bình thường.
  • Tìm ký tự * (lúc này đã bị đổi thành \*) và thay thế nó bằng .* (cú pháp của Regex nghĩa là "khớp với mọi thứ").
  • Gắn mũ ^ (bắt đầu) và đuôi \z (kết thúc) vào rồi chạy preg_match.

Lời kết

Str::is() là một minh chứng rõ nét cho triết lý thiết kế Developer Experience (DX) của Laravel: Giấu đi sự phức tạp của hệ thống (Regex) và cung cấp cho lập trình viên một giao diện sử dụng (API) ngọt ngào, dễ đọc và an toàn nhất có thể.

Lần tới, nếu bài toán chỉ đơn giản là tìm xem chuỗi có bắt đầu, kết thúc, hay chứa một từ khóa nào đó không, hãy cất "khẩu súng ngắm" Regex đi và dùng Str::is(). Code của bạn sẽ sạch sẽ và thanh lịch hơn rất nhiều!


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.