PHP Autoloading là gì? PSR-4 autoloading với Composer

1. PSR là gì?

PSR viết tắt của cụm từ PHP Standard Recommendation là các tiêu chuẩn viết code trong ngôn ngữ PHP được đưa ra bởi tổ chức PHP-FIG (PHP Framework Interop Group). PSR có rất nhiều các tiêu chuẩn khác nhau từ PSR-0 đến PSR-19, mỗi tài liệu đặc tả về những tiêu chuẩn viết code khác nhau cho những công việc khác nhau trong lập trình PHP.

Thiết lập tiêu chuẩn viết code là rất quan trọng trong lập trình theo nhóm, nó giúp code dễ đọc, dễ phát hiện sai sót khi kiểm tra bởi các thành viên khác nhau trong nhóm. Tiêu chuẩn viết mã trong PHP là rất khác nhau giữa các framework và ngay cả các phiên bản PHP khác nhau, ví dụ tên phương thức có thể viết theo nhiều kiểu khác nhau như camelCase, snake_case… hoặc một ví dụ khác về cách thức sử dụng các thư viện PHP ngoài bằng cách sử dụng include thuần túy hoặc sử dụng tiêu chuẩn autoload. Chính vì vậy, PSR được hiệp hội phát triển framework ngồi lại và đưa ra các tiêu chuẩn chung cho viết code PHP.

Trong viết code PHP có 4 tiêu chuẩn thường thấy nhất là PSR-0, PSR-1, PSR-2 và PSR-4, chúng ta cùng xem chúng là những tiêu chuẩn gì? PSR-0 và PSR-4 là tiêu chuẩn về đặt tên namespace và cách load các thư viện PHP tự động. Từ tháng 10 năm 2014, tiêu chuẩn PSR-0 không còn được dùng nữa và khuyến cáo chuyển sang PSR-4. PSR-1 và PSR-2 là các tiêu chuẩn cơ bản về viết mã nguồn và hiện PSR-2 được coi là tiêu chuẩn phổ biến cho “phong cách” viết code.

2. Autoloading là gì?

Composer là một công cụ tuyệt vời cho các lập trình viên PHP, nó giúp cho việc quản lý các gói thư viện dễ dàng. Trong bài viết này chúng ta không đi sâu vào composer mà chỉ tìm hiểu cách thức composer quản lý sự phụ thuộc giữa các gói thư viện thông qua autoloading. Vậy autoloading là gì?

Vấn đề: Khi chúng ta viết một ứng dụng cho sử dụng một danh sách dài các thư viện, ở mỗi file code PHP chúng ta phải thực hiện include chúng vào những đoạn nào có gọi đến các class này, nếu danh sách này dài hàng vài chục dòng thì quả là vấn đề.

Giải pháp: include tất cả các class này ở phần đầu mỗi file PHP.

Giải pháp tốt hơn: Ở những đâu cần gọi đến các class này, thực hiện tải chúng ở thời điểm đó, như vậy ứng dụng không cần tải tất cả các class trong các thư viện cho tất cả các file PHP và chi tiết hơn là các phiên làm việc. Cách thức tải và sử dụng các class như vậy gọi là autoloading.

3. Tạo autoloader riêng

Để hiểu rõ cơ chế autoloading, chúng ta sẽ cùng nhau thử tạo ra một autoloader riêng. Bắt đầu bằng một ví dụ mà chúng ta thường viết kiểu này trước đây:

Chúng ta có hai Class A và B ở hai file khác nhau A.php và B.php

<?php
// Classes/A.php
class A {}

<?php
// Classes/B.php
class B {}

Trong một file PHP chúng ta muốn gọi đến các Class A và B thì chúng ta phải thực hiện include các class này vào:

<?php
// index.php
include_once 'Classes/A.php';
include_once 'Classes/B.php';
// load A class
$a = new A();
// check the list of all loaded files
var_dump(get_included_files());

Kết quả khi chạy index.php như sau:

array(3) { 
	[0]=> string(35) "C:\Laragon\www\autoloader\index.php" 
	[1]=> string(39) "C:\Laragon\www\autoloader\Classes\A.php" 
	[2]=> string(39) "C:\Laragon\www\autoloader\Classes\B.php" 
}

Như vậy, toàn bộ các class được include vào index.php. Nếu chúng ta chỉ có 2 Class A và B thì không có vấn đề gì cả, khi số lượng class lên đến hàng 100 thậm chí hàng 1000, những ứng dụng hiện đại sử dụng các gói thư viện ngoài có khi lên đến cả triệu class thì cách thức viết code như vậy sẽ không thể thực hiện được, chúng ta cần đến autoloader. Cùng xem cách thức autoloading thực hiện bởi autoloader đơn giản sau:

<?php
// index.php
function my_autoloader($class) {
  include 'Classes/' . $class . '.php';
}
// register the autoloader
spl_autoload_register('my_autoloader');
// load A class
$b = new A();
// check the list of all loaded files
var_dump(get_included_files());

Như vậy trong function my_autoloader() chúng ta đã thực hiện việc ánh xạ giữa tên class và đường dẫn đến class để thực hiện include class này. Kết quả như sau:

array(2) { 
	[0]=> string(35) "C:\Laragon\www\autoloader\index.php" 
	[1]=> string(39) "C:\Laragon\www\autoloader\Classes\A.php" 
}

Như vậy chỉ có class nào cần gọi đến thì mới được include vào. Cách ánh xạ này đã giúp chúng ta có thể autoloading tuy còn một số nhược điểm như sau:

  • Tên file phải trùng tên với tên class.
  • Mỗi file chỉ được chứa duy nhất một class.
  • Tên file và tên class là phân biệt chữ hoa chữ thường.

Những tình huống này được xử lý trong autoloader của công cụ composer.

4. Autoloading với composer

Trong phần này chúng ta giả định đã cài đặt composer (Tham khảo bài viết Composer công cụ không thể thiếu cho các dự án PHP). Trong thư mục gốc của web server chúng ta có thể thực hiện lệnh composer xem như thế nào.

Composer command

Composer làm việc với một file thiết lập có định dạng json là composer.json được thêm vào trong thư mục gốc của dự án. Thực hiện tạo ra bằng lệnh composer init hoặc có thể tạo một file text và đặt tên là composer.json. Trong ví dụ này khá đơn giản không có thiết lập gì nên chúng ta đưa vào nội dung { } là bao của nội dung json.

Tiếp đến, thực hiện lệnh composer install, nó sẽ tạo ra thư mục vendor chứa các gói thư viện ngoài mà bạn muốn sử dụng và file autoload.php.

Tạo composer.json và vendor autoload bằng composer command

Thay đổi nội dung file composer.json để composer sẽ tự động tạo lại file autoload.php. Có 4 cách autoloading trong composer là:

  • File base autoloading
  • Classmap Based Autoloading
  • PSR-0 Autoloading
  • PSR-4 Autoloading

Trong bài viết này chúng ta sẽ sử dụng PSR-4 Autoloading, thay đổi nội dung composer.json như sau:

{
    "autoload": {
		"psr-4": {
			"Classes\\": "Classes"
		}
	}
}

Để composer tự động tạo ra file autoload thực hiện lệnh composer dump-autoload. Khi đó mở file vendor/composer/autoload_psr4.php chúng ta thấy composer đã tự động sinh code autoloading

<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'Classes\\' => array($baseDir . '/Classes'),
);

Để sử dụng autoloader này trong file index.php chúng ta thực hiện include mỗi autoloader này vào:

<?php

require('vendor/autoload.php');
use App\B;

$b = new B();
var_dump(get_included_files());

Thực hiện chúng ta thấy rằng, ứng dụng chỉ load mỗi class B mà không load class A:

array(6) { 
	[0]=> string(35) "C:\Laragon\www\autoloader\index.php" 
	[1]=> string(45) "C:\Laragon\www\autoloader\vendor\autoload.php" 
	[2]=> string(59) "C:\Laragon\www\autoloader\vendor\composer\autoload_real.php" 
	[3]=> string(57) "C:\Laragon\www\autoloader\vendor\composer\ClassLoader.php" 
	[4]=> string(61) "C:\Laragon\www\autoloader\vendor\composer\autoload_static.php" 
	[5]=> string(39) "C:\Laragon\www\autoloader\Classes\B.php" 
}

Ở đây chúng ta thấy ứng dụng load cả các file của composer tuy nhiên khi số lượng class tăng lên hàng trăm, hàng nghìn thì autoloader thật sự mới phát huy tác dụng.

5. Lời kết

Qua bài viết chúng ta hiểu thêm về khái niệm các tiêu chuẩn lập trình trong PHP như PSR-0, PSR-4, khái niệm autoloading và được thực hành PSR-4 autoloading với công cụ Composer. Những kiến thức cơ bản này sẽ đi cùng bạn trong suốt quá trình làm việc với các framework viết bằng PHP nói chung và framework Laravel nói riêng.

Add Comment