簡體   English   中英

PHP Package 的自動加載文件 - get_declared_classes() 未返回預期結果

[英]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-reflectioncomposer.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 樣式)。 我對你的項目一無所知,所以如果你仍然想自己嘗試一下,一些建議:

  • Composer 自動加載器配置在他們的架構中,其他信息可在自動加載的優化部分獲得。
  • 請記住,調用requireinclude會返回自動加載器實例。 class不是@internal ,這意味着公共接口可以穩定使用。
  • 另一件值得知道的事情是,在//vendor-dir/composer/installed.json中,您可以找到所有已安裝軟件包的列表以及有關dev安裝的一些詳細信息。
  • installed.json的格式/布局取決於 composer 版本,如果您想支持所有Composer 版本,這很重要。
  • 我不知道所有版本都有作曲家配置矩陣/更改日志。 進行自己的研究。
  • Composer 中有四種自動加載器: psr psr-0classmap psr-4 、類映射和files (已記錄)。
  • 文件擴展名為*.php*.inc (已記錄)。
  • classmap可以排除,帶有*** globs,如果 exclude 選項參數中沒有 globs,則后者會隱式附加(已記錄)。
  • Composer 還包含 class 掃描器,用於 class map 創建。 IIRC 它是內部的,但看起來相對容易提取,因為它只有約 60 行直接代碼,其中大部分是正則表達式操作。 在我檢查的時候,正則表達式和周圍的處理看起來相當經過實戰驗證。 如果你想像Composer 那樣接近--optimize / class-map generation,你可能需要這個。
  • 預計偶爾會遇到 Symfony 或 Phpunit 文件。

  1. 比較“Inspecting code and dependencies of a composer-based project”

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM