通过Composer 2自动加载器,Laravel基类找不到Trait。
通过Composer 2自动加载器,Laravel基类找不到Trait。
我正在使用较新版本的PHP、Laravel和Composer 2进行Laravel项目开发。在我写这篇文章的时候,我在已有的几个特性文件旁边添加了一个新的app/Traits/MyTrait.php
文件,但不幸的是,Composer无论如何都无法检测到这个新文件。我得到了以下错误信息:Trait 'App\Traits\MyTrait' not found
。类似于:Laravel Custom Trait Not Found。下面是代码的一般布局:
# app/Traits/MyTrait.php:# app/Notifications/MyBaseClass.php:# app/Notifications/MyChildClass.php奇怪的是,这段代码在我的本地开发环境中运行得很好,但无论我尝试什么,它在部署到运行在Docker容器中的服务器时都无法工作。我尝试了我能想到的一切,比如在
composer.json
中保存"optimize-autoloader": true
,并在部署过程中运行composer dump-autoload -o
,但没有任何修复的效果:https://getcomposer.org/doc/articles/autoloader-optimization.md。我担心Composer或Laravel可能没有正确地测试这种继承组合,所以这可能是工具中的一个bug。如果情况变得越来越糟,我将尝试以下(可能具有破坏性的)解决方法:
- 调用
composer dump-autoload -o
(在部署过程中速度非常慢,因为这是一个大型项目,而且到目前为止似乎也没有修复它的效果) - 在每次部署之前通过
rm vendor/composer/autoload_classmap.php
、rm vendor/composer/autoload_psr4.php
和/或rm vendor/composer/autoload_namespaces.php
(或类似的方法)删除vendor
文件夹中的文件,以强制Composer重新构建。 - 通过
rm -rf vendor
删除
这个可怕的部分是我们必须对我们的部署过程完全有信心。我们不能在服务器开发环境中通过手动删除vendor
等内容来解决问题,然后在生产部署中失败,因为Composer在其vendor
文件夹中遇到陈旧数据而绊倒。我的直觉是,这正是正在发生的事情,可能是由于从Composer 1升级到Composer 2或版本更改,或者是最近几个月工作中的陈旧缓存文件。即使有一个验证,比如"这个最小的示例项目在Docker上部署对我们来说是可行的",也将有助于缩小问题范围。编辑:这是一个关于Composer自动加载器工作原理的有用资源:https://jinoantony.com/blog/how-composer-autoloads-php-files。
Laravel基类无法通过Composer 2自动加载器找到的Trait是什么原因?以及如何解决?
问题的出现原因是文件名的大小写问题。最初,文件名以小写字母开头,如apiResponser.php
。后来,我对文件进行了一些更改,并将文件名改为ApiResponser.php
,然后将其部署到生产环境,但是... 哎呀,出现了问题。
我遇到了同样的问题。唯一解决方法是进行git名称替换:
git mv app/Traits/apiResponser.php app/Traits/ApiResponser.php
通过这种方式,我成功解决了问题。我知道你可能采用了其他方法来解决这个问题,但这种解决方法可能会帮助到其他开发者。
问题出现的原因是AWS上的容器/文件系统区分大小写,而我的本地开发环境(macOS)是不区分大小写的。
我原本的Trait(保密)在其名称结尾处是以URL
结尾的,但是我在基类中引用它时,路径和使用的名称是Url
。
所以这个问题与Trait、基类或Composer无关。在部署期间,也不需要修改composer.json
或调用的方式。但是我认为最佳实践仍然是在composer.json
中加入以下内容,我目前在本地开发中也是这样使用的(好坏如何?):
"config": {
"optimize-autoloader": true
},
行业内的真正问题是:
- 模糊的错误信息
- 代码没有努力去深入查找实际的原因(例如,尝试以不区分大小写的方式加载并在找到时返回警告)
- 用户没有行动项(您是否检查了大小写?检查了文件是否存在?检查了文件权限?等等,将这些写入错误消息本身,并可能附带指向支持页面/论坛的链接)
由于设计上不方便ssh进入服务器,所以为了排除故障,我将以下内容暂时提交到了我的分支上:
# app/Http/Controllers/TestController.php class TestController extends Controller { public function test() { return response('<pre>' . '# /var/www/html/vendor/composer/autoload_classmap.php' . "\n" . file_get_contents('/var/www/html/vendor/composer/autoload_classmap.php') . "\n" . '# /var/www/html/vendor/composer/autoload_files.php' . "\n" . file_get_contents('/var/www/html/vendor/composer/autoload_files.php') . "\n" . '# /var/www/html/vendor/composer/autoload_namespaces.php' . "\n" . file_get_contents('/var/www/html/vendor/composer/autoload_namespaces.php') . "\n" . '# /var/www/html/vendor/composer/autoload_psr4.php' . "\n" . file_get_contents('/var/www/html/vendor/composer/autoload_psr4.php') . "\n" . '# /var/www/html/vendor/composer/autoload_real.php' . "\n" . file_get_contents('/var/www/html/vendor/composer/autoload_real.php') . "\n" . '# /var/www/html/vendor/composer/autoload_static.php' . "\n" . file_get_contents('/var/www/html/vendor/composer/autoload_static.php') . "\n" ); } } # routes/api.php Route::get('/test', 'TestController');
然后在GitLab中部署未合并的代码,并将响应与AWS Cloudwatch中的错误进行比较,这时候错误的拼写错误就会显现出来。
然后我使用以下命令移除了临时提交:
git reset --soft HEAD^
并使用以下命令强制推送了我的分支:
git push --force-with-lease
因此,我能够解决这个问题,而不影响我们的CI/CD设置或永久地将代码提交到develop或master分支。
我已经做了很多年开发,甚至怀疑这里存在大小写敏感的问题,但有时我们对问题太过于熟悉。如果您陷入代码中并即将发作焦虑,那么有另一双眼睛从头原理上审查您的思考过程会有所帮助。
我还需要找出如何将本地的Docker容器也设置为区分大小写,以与服务器匹配(因为这是使用Docker容器的初衷)。