Tại Sao Bạn Nên Chạy PHPStan Ở Level 9 Trên Laravel

· 4 min read

Gần đây tôi đã nâng level PHPStan trên blog này từ 5 lên 9 (mức tối đa). Kết quả là hơn 300 lỗi. Sửa chúng mất cả cuối tuần, nhưng đã phát hiện ra những bug tinh vi chắc chắn sẽ gây crash runtime trong production.

PHPStan là gì?

PHP là ngôn ngữ dynamic, loosely-typed. Điều này tốt cho tốc độ phát triển nhưng tệ cho độ tin cậy. PHPStan đọc code của bạn mà không chạy nó và tìm kiếm các không khớp:

  • Truyền string cho hàm đang mong đợi int.
  • Gọi method trên biến có thể là null.
  • Truy cập property không tồn tại.

Các Level

  • Level 0: Kiểm tra cơ bản, class không xác định, function không xác định.
  • Level 5: Kiểm tra kiểu của các argument truyền cho method.
  • Level 9: Kiểm tra nghiêm ngặt kiểu mixed. Bạn không thể làm bất cứ điều gì với kiểu mixed chuyên biệt trừ khi bạn kiểm tra nó trước.

Cấu Hình Larastan

PHPStan tiêu chuẩn gặp khó khăn với magic của Laravel (Facade, dynamic property của Eloquent). Bạn cần Larastan.

phpstan.neon:

includes:
    - vendor/larastan/larastan/extension.neon

parameters:
    paths:
        - app/

    # Bắt đầu cao, hạ xuống nếu quá tải. Khuyến nghị: 5
    level: 8

    ignoreErrors:
        # Bỏ qua các false positive cụ thể
        - '#Call to an undefined method Illuminate\\Database\\Eloquent\\Builder::.*#'

Thách Thức Phổ Biến & Cách Sửa

1. Vấn Đề "Maybe Null"

PHPStan ghét khi bạn giả định query thường tìm thấy kết quả.

// Lỗi: Method name() được gọi trên User|null
$user = User::find(1);
echo $user->name; 

Cách sửa: Xử lý trường hợp null một cách rõ ràng.

$user = User::find(1);
if (!$user) {
    abort(404);
}
echo $user->name; // PHPStan biết $user là User ở đây

2. Generic trong Laravel Collection

Đây là điểm đau phổ biến nhất ở Level 9. PHPStan muốn biết cái gì trong Collection hoặc Array đó.

Không tốt:

public function getTags(): array { ... }

Tốt:

/**
 * @return array<int, string>
 */
public function getTags(): array { ... }

Eloquent Collection:

/**
 * @return Collection<int, \App\Models\Post>
 */
public function getPosts(): Collection { ... }

3. Kiểu mixed

Ở Level 9, nếu bạn json_decode thứ gì đó, bạn nhận được mixed. Bạn không thể truy cập property trên mixed nghiêm ngặt.

$data = json_decode($json);
// Lỗi: Không thể truy cập property $id trên mixed.
echo $data->id;

Cách sửa: Dùng assertion.

$data = json_decode($json);
assert($data instanceof \stdClass);
echo $data->id;

Tại Sao Phải Bận Tâm?

  1. Sự Tự Tin: Khi tôi refactor một Service cốt lõi, nếu PHPStan pass, tôi 95% chắc chắn tôi không phá vỡ contract.
  2. Tài Liệu: Thêm @var@return type đóng vai trò như tài liệu tuyệt vời cho bản thân tương lai của bạn.
  3. Không còn Call to a member function on null: Đây là mục lỗi PHP log #1. PHPStan loại bỏ nó hoàn toàn.

Kết Luận

Type là bạn. Strict type là bạn thân nhất. Tăng dial trên PHPStan và ngủ ngon hơn vào ban đêm.

Bình luận