程式狂想筆記

一個攻城師奮鬥史

0%

composer使用psr0,psr4,classmap,files自動載入筆記心得

上次小玩 composer 的自動載入
但今天使用 autoload
發現我還不是很了解他的運作原理
psr0,psr4 差別也看不是很出來他們的差別
不過說真的,網路上幾乎都是忽略掉 psr0
可能也不要花太多心力在上面吧

先講講 composer 自動載入原理
原本想說他是載入 php 會自動載入全部
但無聊看了一下vendor/autoload.php原碼
裡面有用到spl_autoload
所以應該都是基於這個方式去自動載入

但這種自動載入跟檔名Class類別有關係

1
2
我之前測試classmap,只要檔名沒對到,`use function xxx`沒吃到
但是調整對的檔名,`use function xxx`就會吃到

上面那段是我無聊自己試的,其實正常不會用 use function
一個 php 一個 class 是最好的方式

classmap

這個指定相關目錄裡所有 php 都會載入 php 裡面的 class
但 php 未包含 class 不會載入進去
這個也很常在 composer 看到
但先說說我自己測試踩到一個雷

當載入沒宣告namespace時候
預設是會自動載入到全域 namespace
但是全域 namespace 不須要做use xxx
這時候做use xxx會發生錯誤
使用會造成錯誤
Warning: The use statement with non-compound name 'xxx' has no effect
這個別的網頁很少介紹這個
詳細 laravel 的 dataseeder.php 就是這樣設定的
檔案 autoload_classmap.php

1
'DatabaseSeeder' => $baseDir . '/database/seeds/DatabaseSeeder.php',

files

載入指定的 PHP 都會載入進來,重點 class 也都會,其實這邊也可以做 namespace
但好像大家用全域 namespace 比較多
還是別亂用好了 XD

PSR0

這篇已經被廢棄了!!建議可以跳過這邊
不然會跟 PSR4 搞混,千萬不要像我走火入魔!!!!
現在我還沒有看過 composer.json 有用到

1
2
3
"psr-0": {
"Psr0\\Lib\\": "psr0/lib/src/"
},

上面簡單講,就是”psr0/lib/src/“所存在 PSR0/lib/根目錄地方
所以對應項面檔案位置 psr0/lib/src/Psr0/Lib/Psr0LibClass.php

psr0/lib/src/Psr0/Lib/Psr0LibClass.php

1
2
3
4
5
6
7
8
9
10
11
<?php
// psr-0: "Psr0\\Lib\\": "psr0/lib/src/"
namespace Psr0\Lib;

class Psr0LibClass
{
public static function index()
{
echo __CLASS__ . "@" . __FILE__ . PHP_EOL;
}
}

PSR4

這個也很常在 composer.json 看到
相信剛入門一定對下面倒數兩行傻了

1
2
3
4
"psr-4": {
"Psr4\\Lib\\": "psr4/lib/src/",
"App\\Controllers\\": "app/controllers/",
"App\\Models\\": "app/models/"

psr4/lib/src/Psr4LibClass.php

1
2
3
4
5
6
7
8
9
10
11
<?php
// psr-4: "Psr4\\Lib\\": "psr4/lib/src/"
namespace Psr4\Lib;

class Psr4LibClass
{
public static function index()
{
echo __CLASS__ . "@" . __FILE__ . PHP_EOL;
}
}

App\\Controllers\\App\\Models\\怎麼可以投同時宣告
這邊先講我怎麼看這段在幹嘛
psr4/lib/src/目錄下,都已 Psr4\Lib\ namespace 宣告為主
以此類推
App\\Controllers\\app/controllers/
App\\Models\\app/models/

好了,App\\Controllers\\App\\Models\\怎麼可以投同時宣告
為什麼不要用'App\\': 'app'
千锋最新 php 视频教程完整 psr4Autoload 类_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
看這邊解釋,講如這樣用App/Controllers/Contollers.php
不需要寫use App/Controllers/Controllers這麼繞口令

當然 App 資料夾不需要全部東西當 namespace,或者也可以把 namespace 客製化改短一點
EX:

1
2
"Controllers\\": "app/controllers/",
"Models\\": "app/models/"

相信看很難懂,實作比較快
composer 自动载入 autoload 的使用详解 psr0/psr4/classmap/files - big_cat - 开源中国
看這裡面內容,把所有 code 都在本機跑一下,很容易理解php -S 0.0.0.0:8000

autoload 他怎麼知道載入你自己 lib,跟 vendor 上的 lib

1
2
3
4
5
6
7
8
9

// autoload_classmap.php @generated by Composer

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

...
'App\\VoteOption' => $baseDir . '/app/VoteOption.php',
'ArithmeticError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php',

$vendorDir試紙 vendor 路徑
當然做 dirname 就能抓到$baseDir,你自己寫的程式自然就會讀到

總結

最後,新增 psr0/psr4 跟修改 classmap,記得做compser dump-autoload
你說我怎麼沒有提到 psr0_問題,我已經不想深入太多,可參考別的頁面說明
最後 psr 是 Fig 訂出來的規範,實際你要怎麼載入 php 有很多種方法
當然最好一個檔案一個 class,大小寫路徑可能也要注意(雖然 php namespace 不分大小寫…)
但是了解這種載入機制,以後寫元件都是比較好的切入

範例可以參考
malagege/PHP_composer_autoload_demo: PHP composer autoload 簡單實例 demo

參考來源: