在 2012 年以前,PHP 套件管理工具 Composer 還沒問世,安裝套件的方式的是從網路上下載,然後放到專案中的某個目錄,接著用 include
或 require
關鍵字來載入套件。
但在 2020 年的今天,當我們完成了一個 PHP 套件,很開心地想要發表這個作品給社群裡的大家知道,如果不支援 Composer,恐怕會乏人問津,很少會有開發者會對安裝個套件還得使用遠古時代安裝方式的套件感到興趣,主要原因有三項:
讓作品支援 PSR-4 自動載入的功能是最好的方式唷。
ClassName
指的是類別 (class)、特性 (traits)、介面 (interface) 及其它類似的結構。
完整領域類別名稱 (fully qualified class name) 為以下形式:
例:
\<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
<NamespaceName>
指的是命名空間。(\<SubNamespaceNames>)*
指的是下一層的命名空間。(不一定需要,如有使用也無限制層數)
.php
檔案名稱一致。自動載入程式 (autoloader) 不得丟出任何異常 (exception)、不得產生任何級別的錯誤訊息,也不能有任何的回傳值。
完整領域類別名稱 | 命名空間前輟 | 基本目錄 | 結果檔案路徑 |
---|---|---|---|
\Acme\Log\Writer\File_Writer |
Acme\Log\Writer |
./acme-log-writer/lib/ |
./acme-log-writer/lib/File_Writer.php |
\Aura\Web\Response\Status |
Aura\Web |
/path/to/aura-web/src/ |
/path/to/aura-web/src/Response/Status.php |
\Symfony\Core\Request |
Symfony\Core |
./vendor/Symfony/Core/ |
./vendor/Symfony/Core/Request.php |
\Zend\Acl |
Zend |
/usr/includes/Zend/ |
/usr/includes/Zend/Acl.php |
利用 spl_autoload_register
這個函式來註冊自己的自動載入機制。配合 PSR-4 的規範,我們來實作一個自動載入程式,在後續建立自己作品並把作品要發佈到 Composer 的時候,會用在 composer.json
這個檔案設定載入方式為 PSR-4。
autoload.php
spl_autoload_register
的函式。spl_autoload_register
。autoload.php
。autoload.php
。範例:
function psr_http_autoload($className)
{
$prefix = 'Shieldon\\';
$dir = __DIR__ . '/src';
if (0 === strpos($className, $prefix . 'Psr')) {
$parts = explode('\\', substr($className, strlen($prefix)));
$filepath = $dir . '/' . implode('/', $parts) . '.php';
echo $filepath . '<br >';
if (is_file($filepath)) {
require $filepath;
}
}
}
範例:
function psr_http_register()
{
spl_autoload_register('psr_http_autoload', true, false);
}
psr_http_register();
這個範例取自筆者的作品,也是明天筆者會介紹的 PSR-7, PSR-15, PSR-17 的內容。
這個套件的目錄結構如圖:
在這個例子中:
Shieldon
src
Psr7
, Psr15
, Psr17
(大小寫要一致)例如 ServerRequest.php 它的「完整領域類別名稱」為:
Shieldon\Psr7\ServerRequest
命名空間為:
Shieldon\Psr7
完整的範例:
<?php
/*
* This file is part of the Shieldon package.
*
* (c) Terry L. <contact@terryl.in>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
/**
* Register to PSR-4 autoloader.
*
* @return void
*/
function psr_http_register()
{
spl_autoload_register('psr_http_autoload', true, false);
}
/**
* PSR-4 autoloader.
*
* @param string $className
*
* @return void
*/
function psr_http_autoload($className)
{
$prefix = 'Shieldon\\';
$dir = __DIR__ . '/src';
if (0 === strpos($className, $prefix . 'Psr')) {
$parts = explode('\\', substr($className, strlen($prefix)));
$filepath = $dir . '/' . implode('/', $parts) . '.php';
if (is_file($filepath)) {
require $filepath;
}
}
}
psr_http_register();
逐行說明:
if (0 === strpos($className, $prefix . 'Psr')) {
實作載入檔案時,先檢查 $className 是否含有 Shieldon\Psr
字串,如果有的話,再進入下面的載入流程。
$parts = explode('\\', substr($className, strlen($prefix)));
$filepath = $dir . '/' . implode('/', $parts) . '.php';
把「結尾的類別名稱」取出,並得到該 .php
檔案的絕對路徑。
if (is_file($filepath)) {
require $filepath;
}
如果該路徑是一個檔案,就載入它。
這是筆者的套件 psr-http 的自動載入程式。授權條款為 MIT,您可以稍加修改用在自己的專案作品。
PSR-4 的規範重點在於,類別的名稱與命名空間名稱與檔案目錄名稱的對應,只要保持名稱及大小寫一致即可。藉由引用筆者的實際作品,希望能幫助大家更快理解並採用 PSR-4 在自己的專案作品中喔!
本文同步更新於 TerryL 部落格 Day 12 - PHP 自動載入機制:PSR-4,歡迎前往討論。