[英]Autoload files for PHP Package - get_declared_classes() not returning expected results
我在這里創建一個 package
這是一個標准的作曲家 PHP package 與 Symfony 命令生成 Avro 文件。
在bin/avro
目錄中注冊 package 命令時,我添加以下內容
require file_exists(__DIR__ . '/../vendor/autoload.php')
? __DIR__ . '/../vendor/autoload.php'
: __DIR__ . '/../../../../vendor/autoload.php';
如果我的理解是正確的,這應該會自動加載加載了 package 的項目的所有文件。
例如,我在一個空的 Laravel 項目中運行以下命令
composer require lukecurtis93/avrogenerate
./vendor/bin/avro generate
此處使用get_declared_classes()
的代碼 - 摘錄:
// ...
$arr = [];
foreach (get_declared_classes() as $className) {
if (in_array(Avroable::class, class_implements($className))) {
$arr[] = $className;
}
}
// ...
- 不返回存儲在我的App/Models
目錄中的任何文件,例如 Laravel 應用程序(或與此相關的任何其他應用程序)中的文件。
我做錯了什么? 這些文件不應該從get_declared_classes()
獲得嗎? 我需要為 package 做額外的配置嗎?
如果我的理解是正確的,這應該會自動加載加載了 package 的項目的所有文件。
您誤解了“自動加載”在這種情況下的含義。 它並不意味着“一次自動查找並加載所有類”; 這意味着“按需自動加載類”。
在官方手冊中有關於這是如何工作的描述。 簡短的版本是,每當您嘗試使用尚未定義的 class 時,PHP 會將 class 名稱傳遞給回調; 該回調可以做任何它喜歡的事情來定義 class,通常根據一些命名約定加載文件。
因此,在您嘗試使用 class 之前,它將保持未定義狀態,並且get_declared_classes
不會知道它。
默認情況下, class_exists
function將觸發自動加載器,這可能對您有所幫助。 如果您確實需要動態列出 package 中的所有類,則需要找到一些其他方法來迭代磁盤上的文件。
我需要為 package 做額外的配置嗎?
當你想使用get_declared_classes()
時,IMSoP 已經解釋了 PHP 自動加載的細節。
另一種方法是重新使用 Composer 類映射,但是它需要生成它, composer dump-autoload
的--optimize
參數可以做到這一點。 鑒於 Composer Autoloader 已被以這種方式轉儲,“已聲明”類的列表很容易獲得:
$autoload = require file_exists(__DIR__ . '/../vendor/autoload.php')
? __DIR__ . '/../vendor/autoload.php'
: __DIR__ . '/../../../../vendor/autoload.php';
$classmap = $autoload->getClassMap();
然后$classmap
是一個關聯數組,其中類名作為鍵,文件的(絕對)路徑(w/相對段)。
缺點是必須使用特定配置轉儲自動加載器。 好處是您可以立即准備就緒。
更好的反思
package roave/better-reflection
為composer.json
和//vendor-dir/composer/installed.json
提供了一個類列表,而不依賴於 Composer 自動加載器的類映射。
您可以將它添加為一個要求,然后它將與自動加載器一起使用。
獲取類列表在他們的文檔1中,這取決於項目的路徑。 您可以將它作為您的實用程序的參數選項,因為我不知道如何從自動加載器實例獲取根項目路徑,以下將假定默認的vendor-dir
配置,YMMV:
$projectAutoload = file_exists(__DIR__ . '/../vendor/autoload.php')
? __DIR__ . '/../vendor/autoload.php'
: __DIR__ . '/../../../../vendor/autoload.php';
$autload = require $projectAutoload;
$projectRoot = dirname($projectAutload, 2);
它沒有實現 100% 的 Composer 自動加載器配置,但我還沒有看到除 Composer 本身之外的其他組件。 僅供參考,當你想知道集成測試時,它在 99.5% 的陣營中,你甚至可能不會錯過你的用例中的任何東西。
$astLocator = (new BetterReflection())->astLocator();
$reflector = new DefaultReflector(new AggregateSourceLocator([
(new MakeLocatorForComposerJsonAndInstalledJson)($projectRoot, $astLocator),
new PhpInternalSourceLocator($astLocator, new ReflectionSourceStubber())
]));
$classes = $reflector->reflectAllClasses();
$classNames = array_map(fn (ReflectionClass $rfl) => $rfl->getName(), $classes);
Better Reflection 也不是馬廄里跑得最快的馬。 擁有不錯的 CPU 和快速的磁盤 I/O。 它的好處是它的功能,在您的特定情況下,您可以使用它進行預覽( get_declared_classes()
保持為空,不涉及自動加載,您可以使用收集到的信息進行 inheritance 檢查,而無需將文件加載到 PHP - 我可以想象這可能對您的實用程序有好處)。
自己寫
在 vendor 文件夾中編寫所有 PHP 文件的臨時加載相對容易,以便get_declared_classes()
之后擁有它們。 但是通過這樣的直接實現,你很容易遇到致命錯誤,這對你的事業沒有幫助,而且如果你想堅持使用 composer 包,你需要給它一些愛。 這還取決於您要支持哪些包(和 package 樣式)。 我對你的項目一無所知,所以如果你仍然想自己嘗試一下,一些建議:
require
或include
會返回自動加載器實例。 class不是@internal
,這意味着公共接口可以穩定使用。//vendor-dir/composer/installed.json
中,您可以找到所有已安裝軟件包的列表以及有關dev
安裝的一些詳細信息。installed.json
的格式/布局取決於 composer 版本,如果您想支持所有Composer 版本,這很重要。psr-0
、 classmap
psr-4
、類映射和files
(已記錄)。*.php
和*.inc
(已記錄)。classmap
可以排除,帶有*
和**
globs,如果 exclude 選項參數中沒有 globs,則后者會隱式附加(已記錄)。--optimize
/ class-map generation,你可能需要這個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.