PHP包自动加载问题:get_declared_classes()未返回预期结果
问题描述
我正在开发一个PHP Composer包,它是带有Symfony命令的标准包,用于生成Avro文件。
在bin/avro文件中注册命令时,我添加了以下代码来加载自动加载文件:
require file_exists(__DIR__ . '/../vendor/autoload.php') ? __DIR__ . '/../vendor/autoload.php' : __DIR__ . '/../../../../vendor/autoload.php';
我以为这样就能自动加载包所在项目的所有文件,于是在一个空Laravel项目中执行了以下命令:
composer require lukecurtis93/avrogenerate ./vendor/bin/avro generate
但在包的DefaultAvroGenerator.php文件中,这段使用get_declared_classes()的代码:
// ... $arr = []; foreach (get_declared_classes() as $className) { if (in_array(Avroable::class, class_implements($className))) { $arr[] = $className; } } // ...
并没有返回Laravel应用中App/Models目录下的任何类(其他目录的类也无法获取)。
请问我哪里操作有误?这些类难道不应该通过get_declared_classes()获取到吗?是否需要为包进行额外配置?
解决方案
问题核心在于PHP自动加载机制和get_declared_classes()的特性:
get_declared_classes()仅返回已经被加载到内存中的类,而Composer的自动加载是延迟加载(懒加载)——只有当代码首次引用某个类时,才会触发文件加载。你的命令执行时,Laravel项目里的App/Models类没有被任何代码引用,自然不会被加载,也就不会出现在返回结果里。- 你当前的自动加载代码是正常的,但它只是让项目的自动加载器可用,并不会主动加载项目内的所有类。
要解决这个问题,推荐两种实用方案:
- 基于Composer规则扫描目标目录
利用Composer的API读取项目的composer.json配置,获取PSR-4命名空间对应的目录(比如Laravel的App/对应App\命名空间),然后递归扫描这些目录下的文件,通过反射机制判断类是否实现了Avroable接口。这种方式不需要用户额外配置,符合PHP生态的自动加载规范。 - 让用户手动配置目标类
提供配置文件(比如Laravel的config/avro-generate.php),让用户把需要生成Avro的类名列在配置中,你的包直接读取配置获取类名即可。这种方式更高效,也能避免不必要的目录扫描。
注意:不要尝试一次性加载项目所有类,这会严重拖慢命令执行速度,只加载你需要处理的目标类即可。
内容的提问来源于stack exchange,提问作者Luke Curtis
相关产品推荐
相关产品推荐

