Menu

Namespace trong PHP: namespace, use và alias

Namespace trong PHP gom các lớp, hàm và hằng số dưới một tiền tố: namespace App\Models; ở đầu tệp, rồi use App\Models\User; ở nơi khác để gọi lớp bằng tên ngắn. Tìm hiểu tên đầy đủ, alias với use ... as, use function, dấu gạch chéo ngược ở đầu cho lớp toàn cục và autoload theo PSR-4.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Namespace trong PHP đặt các lớp, hàm và hằng số dưới một tiền tố để tên của chúng không thể trùng với tên của người khác. Bạn khai báo nó bằng namespace App\Models; làm câu lệnh đầu tiên của tệp, và các tệp khác gọi lớp đó là \App\Models\User, hoặc import nó bằng use App\Models\User; rồi chỉ cần viết User.

Bên trong namespace, User nghĩa là App\Models\User. User::class cho ra tên đầy đủ dưới dạng chuỗi mà không tạo ra gì cả, rất tiện cho việc ghi log và cho autoloader.

Hai namespace trong một tệp

Một dự án thực tế đặt mỗi namespace trong một tệp. Với một ví dụ gói gọn, một tệp có thể chứa nhiều namespace nếu mỗi namespace được bọc trong cặp ngoặc nhọn. Code không thuộc namespace nào đặt trong namespace { }:

Hai lớp cùng tên Order nằm cạnh nhau vì tên đầy đủ của chúng khác nhau. Đó chính là vấn đề namespace giải quyết khi bạn cài thư viện: Order của bạn, Order của một thư viện thanh toán và Order của một thư viện PDF không còn xung đột.

Import bằng use, đặt alias bằng as

Viết \Shop\Order ở khắp nơi thì rườm rà. use ở đầu tệp (hoặc đầu khối namespace) import một tên để bạn dùng dạng ngắn. Khi hai lệnh import có cùng tên ngắn ở cuối, as đặt cho một trong hai một tên khác:

use chỉ tạo một tên ngắn cho phần còn lại của tệp. Nó không nạp tệp hay chạy code, và hoạt động như nhau dù lớp đã tồn tại hay chưa. Bạn cũng có thể import theo nhóm: use Shop\{Order, Invoice};.

use function và use const

Hàm và hằng số trong một namespace được import bằng use function và use const:

Lớp toàn cục cần dấu gạch chéo ngược

Bên trong một namespace, tên lớp không có tiền tố được tìm tương đối theo namespace đó, nên new DateTime() bên trong namespace App; sẽ tìm App\DateTime. Hàm và hằng số thì khác: nếu App\strlen không tồn tại, PHP quay về hàm strlen toàn cục. Lớp thì không bao giờ quay về.

catch (\Error $e) cũng cần dấu gạch chéo ngược vì cùng lý do: không có nó, PHP sẽ tìm App\Error, không bao giờ khớp với lỗi thật, và script dừng lại với một Error không được bắt. Sửa bằng dấu gạch chéo ngược ở đầu như trên, hoặc bằng use DateTime; ở đầu tệp. Điều này cũng đúng với \Exception, \Throwable và mọi lớp có sẵn khác; xem try catch để biết cách bắt chúng.

Autoload và PSR-4

Trong một dự án, mỗi lớp nằm trong tệp riêng, và đường dẫn tệp đi theo namespace. PSR-4 là quy ước cho việc này: một tiền tố namespace ánh xạ tới một thư mục gốc, và phần còn lại của tên trở thành đường dẫn. Một autoloader đăng ký bằng spl_autoload_register() sẽ nạp tệp của lớp vào lần đầu lớp đó được dùng. Khối code này ghi hai tệp lớp ra đĩa rồi autoload chúng:

Mỗi tệp lớp chỉ được nạp một lần, đúng lúc lớp đó được cần đến lần đầu. Trong dự án thực tế, bạn không tự viết hàm này: Composer tạo nó từ vài dòng trong composer.json:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

Sau composer dump-autoload, chỉ một dòng require __DIR__ . '/vendor/autoload.php'; ở đầu script khởi chạy là nạp được mọi lớp App\... khi cần.

Những quy tắc namespace hay gây lỗi

  • namespace phải là câu lệnh đầu tiên trong tệp. Chỉ declare(strict_types=1); và chú thích được đứng trước nó.
  • Lệnh import use có hiệu lực theo từng tệp. Import một lớp trong index.php không làm tên ngắn hoạt động bên trong một tệp được include; mỗi tệp cần các dòng use riêng.
  • use đặt ở cấp ngoài cùng của tệp hoặc khối namespace. Bên trong thân lớp, use mang nghĩa khác: nó đưa một trait vào lớp.
  • Chuỗi không bao giờ được tìm theo namespace: $class = 'User'; new $class(); sẽ tìm User toàn cục. Hãy lưu tên đầy đủ, tốt nhất là bằng User::class.

Quy tắc cuối đáng để kiểm tra nhanh:

Câu hỏi thường gặp

Namespace trong PHP là gì?

Là một tiền tố gom các lớp, interface, hàm và hằng số liên quan lại với nhau, giống một thư mục cho các tên. namespace App\Models; ở đầu tệp đặt lớp User của tệp đó tại App\Models\User, nên nó không thể trùng với User của một thư viện khác.

use trong PHP dùng để làm gì?

use App\Models\User; ở đầu tệp cho phép bạn viết User thay vì tên đầy đủ \App\Models\User trong tệp đó. Nó không nạp hay include gì cả; nạp tệp chứa lớp là việc của autoloader. use ... as Alias; chọn một tên ngắn khác.

Vì sao bị lỗi Class not found bên trong một namespace?

Bên trong namespace App;, tên lớp không có tiền tố được tìm tương đối theo namespace, nên new DateTime() sẽ tìm App\DateTime. Hãy viết new \DateTime() hoặc thêm use DateTime; ở đầu tệp. Hàm và hằng số tự động quay về namespace toàn cục, còn lớp thì không.

Dấu gạch chéo ngược trước tên lớp trong PHP là gì?

Dấu gạch chéo ngược ở đầu biến tên thành tên đầy đủ, tính từ namespace toàn cục: \Exception luôn là lớp Exception có sẵn của PHP, dù code nằm trong namespace nào. Không có nó, tên được tìm tương đối theo namespace hiện tại và các lệnh use.

Namespace liên quan thế nào đến thư mục và PSR-4?

Bản thân PHP không gắn namespace với thư mục. PSR-4 là quy ước làm việc đó: một tiền tố như App\ ánh xạ tới một thư mục như src/, nên App\Models\User nằm ở src/Models/User.php. Autoloader của Composer tuân theo quy ước này, vì vậy hai thứ thường khớp nhau.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu