Autoload hoạt đông như thế nào

Trong lập trình hướng đối tượng với PHP chúng ta thường cố gắng tách các đối tượng ra các file riêng biệt và khi cần đến đối tượng nào thì chúng ta thường include hoặc require chúng vào file thực thi. Từ PHP 5 trở đi bạn có thể sử dụng 1 kỹ thuật khác để làm điều tương tự như vậy đó là autoloading.

 Bạn có thể thực hiện autoloading các class cần thiết bằng cách tự code hoặc sử dụng composer để thực hiện. Trong bài viết này chúng ta sẽ thực hiện autoloading thủ công để các bạn có thể hiểu được cơ chế hoạt động của autoloading trong PHP.

Ví dụ thay vì phải sử dụng hàm include để nạp các file cần thiết như bên dưới

 chúng ta có thể tự động hóa việc này bằng cách sử dụng hàm spl_autoload_register(), hàm này hiện đang được recommend trong PHP 7 để thay thế cho hàm auto_load() của PHP 5

bark();

Đoạn mã trên hoạt động như thế nào?

  • Đầu tiên chúng ta chỉ định đường dẫn đến các file PHP mà chúng ta sẽ tự động load khi nó được gọi thông qua hàm spl_autoload_register(), PHP sẽ truyền class name cần nạp thông qua tham số $className, hiển nhiên là bạn có thể đặt nó thành một tên bất kỳ nào khác.
  • Tiếp theo chúng ta có thể sử dụng các hàm sau để include file vào 
    1. require
    2. require_once
    3. include
    4. include_once
  • Tất cả các hàm này đều có ưu và nhược điểm riêng và lý tưởng nhất là bạn nên sử dụng hàm include_one bởi khi sử dụng hàm này bạn không lo xảy ra lỗi nếu gọi nạp cùng 1 file nhiều lần.
  • Khi bạn khởi tạo hoặc gọi đến tên class nào đó, hàm callback trong spl_autoload_register sẽ được gọi để nạp file chứa class đó vào trình thông dịch.

Nếu có nhiều hàm callback autoload, PHP sẽ tạo 1 queue và thực hiện lần lượt theo thứ tự hàm callback được định nghĩa trong lời gọi hàm 

 cho đến khi nó tìm được class, và nếu sau khi chạy qua tất cả autoload mà không tìm thấy class thì sẽ có exception class not found.

VD nhiều autoload callback, load class trong 2 thư mục includes và classes

src ├── classes │ └── MyClass.php ├── includes ├── index.php

 Output

Try to load /tmp/autoload/src/includes/MyClass.php Try to load /tmp/autoload/src/classes/MyClass.php 

Với hàm _autoload bạn cũng thực hiện tương tự như vậy, tuy nhiên hàm này không còn được khuyên dùng do nó dễ gây ra lỗi conflict nếu như có 1 chỗ nào đó cũng gọi hàm này trong code.

Trong bài viết này, chúng ta sẽ thảo luận về khái niệm cơ bản của autoloading trong PHP và cách mà lớp PHP autoload làm việc với Composer. Bài viết sẽ giải thích tại sao autoloading lại rất quan trọng và chỉ cho bạn cách sử dụng Composer để “autoloading” theo từng bước. Bài viết này cũng giải thích sự khác nhau giữa các kiểu autoloading trong Composer.

Tại sao chúng ta cần Autoloading?

Khi bạn “build” một ứng dụng PHP, bạn có thể sử dụng các thư viện của bên thứ 3 (third-party libraries). Và như bạn biết, nếu bạn muốn sử dụng những thư viện này trong ứng dụng của mình, bạn cần “include” chúng vào mã nguồn của mình bàng việc sử dụng câu lệnh require hoặc include.

Câu lệnh require hoặc include là tốt khi bạn phát triển một ứng dụng nhỏ. Nhưng khi ứng dụng của bạn lớn dần lên, danh sách các câu lệnh require và include sẽ trở nên cồng kềnh, điều này khiến code của bạn trở nên khó quản lý và bảo trì. Một vấn đề khác với phương pháp này là bạn đang tải toàn bộ thư viện trong ứng dụng của mình, bao gồm cả những phần mà bạn không sử dụng. Điều này dẫn đến việc sử dụng các tài nguyên thừa, và ứng dụng của bạn trở nên “nặng” hơn.

Để xử lý vấn đề này, lý tưởng nhất là chỉ tải các lớp khi chúng thực sự cần thiết. Đó là lúc autoloading lên tiếng. Ở mức cơ bản nhất, khi bạn sử dụng một lớp trong ứng dụng, autoloader sẽ kiểm tra xem nó đã được “tải” trước đó chưa, và nếu chưa, autoloader sẽ load các lớp cần thiết vào trong bộ nhớ. Vì vậy lớp được load nhanh khi cần – điều này được gọi là autoloading. Khi bạn sử dụng autoloading, bạn không cần include tất cả các file thư viện một cách thủ công; bạn chỉ cần include autolader file mà chứa logic của autoloading, và các lớp cần thiết sẽ được tự động include.

Ở phần tiếp theo, chúng ta sẽ xem cách autoloading làm việc với Composer. Nhưng trước tiên, tôi sẽ giải thích làm cách nào bạn có thể implement autoloading trong PHP mà không cần Composer.

Autoloading làm việc mà không cần Composer bằng cách nào?

Bạn có thể không nhận ra điều này, nhưng có thể thực hiện tự động tải trong PHP mà không cần Composer bằng cách sử dụng hàm sql_autoload_register(). Hàm này cho phép bạn đăng ký các hàm trong một queue sẽ được triggered thực hiện tuần tự khi PHP load các lớp mà chưa được load trước đó.
Cùng xem ví dụ sau để hiểu các hàm này hoạt động

Trong ví dụ trên, chúng ta đã sử dụngspl_autoload_register()để autoload hàmcustom_autoloader(). Tiếp theo, khi chúng ta có thử khởi tạo lớp FooBar và nếu lớp này đang chưa được include, PHP sẽ thực thi tuần tự các hàm được autoloader quản lý. Và vì vậy, hàm custome_autoloader được gọi, nó bao gồm các file cần thiết và cuối cùng đối tượng được khởi tạo. Trong ví dụ này, ch úng ta chắc chắn rằng lớp FooBar được định nghĩa trong thư mục lib/FooBar.php

Không sử dụng autoloading, bạn sẽ cần sử dụng require hoặc include để include file FooBar. Việc triển khai autoloader khá đơn giản trong ví dụ trên, bạn có thể xây dựng điều này bằng cách đăng ký nhiều autoloader cho các lớp khác nhau.

Tuy nhiên, trong thực tế, bạn sẽ không thường xuyên viết autoloader của riêng mình. Đó là công việc của Composer! Phần tiếp theo, chúng ta sẽ thảo luận về cách sử dụng Composer để tự động tải trong PHP.

Autoloading làm việc với Composer như thế nào?

Trước tiên, hãy đảm bảo cài đặt Composer trên hệ thống của bạn nếu bạn muốn làm theo các ví dụ. Khi nói đến tự động tải với Composer, có nhiều phương pháp khác nhau mà bạn có thể chọn.

Cụ thể, Composer cung cấp bốn phương pháp khác nhau để tự động tải tệp:

  • File autoloading
  • Class-map autoloading
  • PSR-0 autoloading
  • PSR-4 autoloading

Theo Composer documentation, PSR-4 là cách sử dụng được “recommended” và chúng ta sẽ đi qua chi tiết điều đó trong phần tiếp theo. Trong phần này, chúng ta sẽ thảo luận ngắn gọn về ba tùy chọn khác.
Trước khi chúng ta tiếp tục, hãy nhanh chóng xem qua các bước bạn cần thực hiện khi muốn sử dụng tính năng Composer autoloading.

  • Tạo file composer.json trong dự án của bạn ở thư mục root. Nội dung file chứa các chỉ dẫn dựa trên loại tự động tải.
  • Chạy lệnhcomposer dump-autoloadđể tạo các tệp cần thiết mà Composer sẽ sử dụng để autoloading.
  • Include câu lệnh'vendor/autoload.php'ở đầu file mà bạn muốn sử dụng autoloading.

Autoloading theo file thư mục

Tính năng autoloading hoạt động tương tự như include hoặc require cho phép bạn tải toàn bộ file nguồn. Tất cả các file sẽ được tải mỗi khi ứng dụng của bạn chạy. Điều này rất hữu ích để tải các tệp nguồn không sử dụng các lớp.
Để sử dụng file autoloading, chúng ta cung cấp danh sách các file được chỉ ra trong file composer.json như sau:

{ "autoload": { "files": ["lib/Foo.php", "lib/Bar.php"] } }

Ở đây chúng ta cung cấp danh sách các file mà bạn muốn được load tự động bởi Composer. S au khi tạo tệp composer.json trong thư mục gốc của dự án với nội dung trên, bạn chỉ cần chạy lệnhcomposer dump-autoloadđể tạo các file cần thiết được autoload. Chúng sẽ được tạo trong thư mục vendor. Cuối cùng bạn cần thêm câu lệnh

{ "autoload": { "classmap": ["lib"] } }0vào đầu tiên của file, nơi bạn muốn thực hiện autoload với Composer. Code ví dụ như sau:

Câu lệnh

{ "autoload": { "classmap": ["lib"] } }0chắc chắn rằng các file cần thiết sẽ được load tự động.

Autoload theo thư mục

Thay vì tải từng file tự động, chúng ta có thể để Composer tải tự động tất cả các file có trong 1 thư mục được chỉ định. Cú pháp lệnh như sau (chỉnh sửa nội dung file composer.json):

{ "autoload": { "classmap": ["lib"] } }

Chạy lệnhcomposer dump-autoloadvà Composer sẽ đọc các file trong thư mục lib để tạo “bản đồ” các lớp có thể autoload.

Chúng ta đã tìm hiểu vì sao nên dùng Autoloading trong PHP, cách mà lớp autoload  làm việc với Composer qua 2 phương pháp: File autoload, Directory autoload. Tiếp theo chúng ta sẽ nghiên cứu về cách chaỵ autoload với các chuẩn PSR-0 và PSR-4.

PSR-0 là chuẩn cơ bản được đề xuất bởi PHP-FIG. Trong chuẩn PSR-0 cơ bản, bạn cần định nghĩa namespace để định nghĩa các thư viện của bạn. Lớp đủ tiêu chuẩn phải tuân theo cấu trúc

{ "autoload": { "classmap": ["lib"] } }3. Vì vậy các lớp của bạn cần được tạo trong các cấu trúc thư mục tương ứng. Ví dụ khi xem file composer.json như sau:

{ "autoload": { "psr-0": { "Tutsplus\\Library": "src" } } }

Với chuẩn PSR-0 autolading, bạn cần liên kết namespace với các cấu trúc thư mục. Trong ví dụ này chúng ta nói với Composer rằng tất cả mọi thứ trong namespace Tutsplus\Library đã tồn tại trong thư mục src\Tutsplus\Library.

Ví dụ, nếu bạn muốn định nghĩa lớp Foo trong thư mục src\Tutsplus\Library, bạn cần tạo file src\Tutsplus\Library\Foo.php như sau:

Bạn có thể thấy, lớp này được định nghĩa trong namespace Tutsplus\Library. Và tên file giống với tên class. Bây giờ chúng ta sẽ xem làm cách nào để autoload lớp Foo.

Composer lúc này sẽ tự động load lớp Foo từ thư mục src\Tutsplus\Library. Đây là giải thích ngắn gọn về PSR-0 autoloading trong Composer. Tiếp theo chúng ta sẽ tìm hiểu autoloading theo chuẩn PSR-4.

PSR-4 tương tự như PSR-0 ở chỗ bạn cần sử dụng namespaces, nhưng bạn không cần phải bắt chước cấu trúc thư mục với namespaces.

Đối với PSR-0 autoloading, bạn phải “map” các namespace tới các cấu trúc thư mục. Ví dụ nếu bnaj muốn autoload lớp Tutsplus\Library\Foo bạn phải đặt nó trong cấu trúc thư mục src\Tutsplus\Library\Foo.php. Khi sử dụng PSR-4 autoloading, bạn có thể rút ngắn cấu trúc thư mục, để thu được việc bạn có cấu trúc thư mục ngắn gọn và đơn giản hơn nhiều so với việc sử dụng PSR-0 autoloading.

File composer.json với tính năng tự động tải PSR-4 sẽ có dạng như sau:

{ "autoload": { "psr-4": { "Tutsplus\\Library\\": "src" } } }

Một chú ý quan trọng rằng chúng ta thêm cặp dấu

{ "autoload": { "classmap": ["lib"] } }4ở cuối của namespaces. Việc này giúp Composer bất kì file nào bắt đầu với namespace Tutsplus\Library nên được đặt trong thư mục src. Vì vậy bạn không cần tạo thư mục Tutsplus và Library nữa. Ví dụ, nếu bạn muốn request lớp Tutsplus\Library\Foo, Composer sẽ tìm cách load file src\Foo.

Một điều quan trọng nữa là lớp Foo sẽ vẫn được định nghĩa trong namespace Tutsplus\Library; Nó chỉ ra rằng bạn không cần tạo thư mục “bắt chước” các namespace. Nội dung file src\Foo.php vẫn được đặt trong thư mục vật lý src\Tutsplus\Library\Foo.php giống ví dụ trước.

Như bạn thấy PSR-4 cho chúng ta khai báo một cấu trúc thư mục đơn giản, bạn có thể bỏ qua việc tạo các thư mục lồng nhau trong khi vẫn sử dụng không gian tên đầy đủ.

PSR-4 là cách sử dụng autoloading được đề xuất, và nó được sử dụng rộng rãi trong cộng đồng PHP. Bạn nên bắt đầu sử dụng nó trong các ứng dụng của mình nếu bạn chưa làm như vậy!