为了让这件事更有趣,如果我运行composer dump-autoload -o
,事情会很好,但我很好奇,为什么当我首先运行composer update
时会出现错误?我需要弄清真相。快速的解决办法并不能让我内心快乐。
aligajani at Alis-MBP in ~/Projects/saveeo on master ✗ [faaba41c] 4:53
> composer update
> php artisan clear-compiled
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
Package guzzle/guzzle is abandoned, you should avoid using it. Use guzzlehttp/guzzle instead.
Generating autoload files
> php artisan optimize
[ReflectionException]
Class SaveeoBoardObserversBoardEventListener does not exist
BoardEventListener.php(放置在Saveeo/Board/Obstators中)
<?php
namespace SaveeoBoardObservers;
use SaveeoServicesHashIdsContractsHashIds as HashIdService;
class BoardEventListener {
private $hashIdService;
public function __construct(HashIdService $hashIdService) {
$this->hashIdService = $hashIdService;
}
public function whenBoardIsCreated($event) {
$this->hashIdService->syncHashIdValueOnModelChanges($event, 'board');
}
public function whenBoardIsUpdated($event) {
$this->hashIdService->syncHashIdValueOnModelChanges($event, 'board');
}
public function subscribe($events) {
$events->listen(
'SaveeoBoardObserversEventsBoardHasBeenCreated',
'SaveeoBoardObserversBoardEventListener@whenBoardIsCreated'
);
$events->listen(
'SaveeoBoardObserversEventsBoardHasBeenUpdated',
'SaveeoBoardObserversBoardEventListener@whenBoardIsUpdated'
);
}
}
EventServiceProvider.php(位于Saveeo/Providers中)
<?php
namespace SaveeoProviders;
use IlluminateContractsEventsDispatcher as DispatcherContract;
use IlluminateFoundationSupportProvidersEventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
//
];
/**
* The subscriber classes to register.
*
* @var array
*/
protected $subscribe = [
'SaveeoBoardObserversBoardEventListener',
];
/**
* Register any other events for your application.
*
* @param IlluminateContractsEventsDispatcher $events
* @return void
*/
public function boot(DispatcherContract $events) {
parent::boot($events);
//
}
}
这是文件夹结构。这里看不出有什么问题吗?
https://i.stack.imgur.com/JQ2l1.jpg
Composer.json
{
"name": "laravel/laravel",
"description": "The Laravel Framework.",
"keywords": [
"framework",
"laravel"
],
"license": "MIT",
"type": "project",
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.2.*",
"firebase/php-jwt": "~2.0",
"guzzlehttp/guzzle": "5.*",
"guzzlehttp/oauth-subscriber": "0.2.0",
"laravel/socialite": "2.*",
"league/flysystem-aws-s3-v3": "~1.0",
"aws/aws-sdk-php": "3.*",
"bugsnag/bugsnag-laravel": "1.*",
"vinkla/hashids": "^2.3"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
"mockery/mockery": "0.9.*",
"phpunit/phpunit": "~4.0",
"phpspec/phpspec": "~2.1",
"tymon/jwt-auth": "0.5.*",
"symfony/dom-crawler": "~3.0",
"symfony/css-selector": "~3.0"
},
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"Saveeo\": "app/"
}
},
"autoload-dev": {
"classmap": [
"tests/TestCase.php"
]
},
"scripts": {
"post-install-cmd": [
"php artisan clear-compiled",
"php artisan optimize"
],
"pre-update-cmd": [
"php artisan clear-compiled"
],
"post-update-cmd": [
"php artisan optimize"
],
"post-root-package-install": [
"php -r "copy('.env.example', '.env');""
],
"post-create-project-cmd": [
"php artisan key:generate"
]
},
"config": {
"preferred-install": "dist"
}
}
看起来我们将app/目录中类的自动加载命名空间(手动或使用artisan app:name
)从composer中的App
(默认值)更改为Saveeo
。json:
"autoload": { "psr-4": { "Saveeo\": "app/" } },
当我们理解其含义时,这是完美的。当我们查看导致异常的文件(括号中的名称空间)的项目文件夹结构时,我们可以看到问题中描述的问题:
app (Saveeo)
├── Saveeo (SaveeoSaveeo)
│ ├── Board (SaveeoSaveeoBoard)
│ │ ├── Observers (SaveeoSaveeoBoardObservers)
│ │ │ ├── BoardEventListener
└── ...
为了与PSR-4兼容,BoardEventListener
的命名空间应该是SaveeoSaveeoBoardObservers
,因为它存在于嵌套在app/下的Saveeo/件名和路径而不是文件中声明的命名空间来解析类文件[Composer从类文件中读取命名空间以创建优化的类映射,只要顶级命名空间匹配即可。请参阅更新。]
如果我们不想更改应用程序的目录结构,并且也不想在命名空间中使用两个Saveeo
,我们可以配置Composer在自动加载类时将两个目录合并到同一命名空间中:
"autoload": {
"psr-4": {
"Saveeo\": [ "app/", "app/Saveeo/" ]
}
},
并记住CCD_ 9。
它有效,但我不建议在实践中这样做。它偏离了PSR-4标准,使应用程序容易受到名称空间冲突的影响,并且可能会使项目的其他工作人员感到困惑。我建议您展平Saveeo
命名空间和目录,或者为嵌套目录中的类选择不同的命名空间。
。。。如果我运行
composer dump-autoload -o
,事情会很好,但我很好奇为什么当我运行composer update
时会出现错误。。。?
生成自动加载缓存文件时,Composer实际上不会执行您的代码。然而,在大多数Laravel应用程序(直到5.5)中,artisan optimize
命令在composer update
之后运行,确实启动应用程序以执行其操作,因此执行问题代码,我们看到异常。
更新:
如果使用
SaveeoBoardetc
与使用SaveeoSaveeoBoardetc
相比是错误的,那么整个应用程序中的其他文件将不起作用,但它们起作用。
当我们生成优化的自动加载器时,我们可以从技术上使用与项目目录结构不匹配的非PSR-4命名空间,就像我们准备生产应用程序一样:
composer dump-autoload --optimize
这是因为Composer将扫描每个类文件的名称空间,以创建静态类映射。当我们不指定--optimize
时,Composer依赖于动态自动加载,它将文件路径与命名空间匹配,因此无法解决非标准的命名空间或目录结构。
有问题的项目的名称空间在很大程度上是有效的,尽管它没有遵循PSR-4,因为我们使用dump-autoload
的-o
选项手动转储优化的自动加载器。但是,我们看到了错误消息,因为composer update
在运行更新之前删除了缓存的类映射,因此,当artisan optimize
命令运行时,类映射不再包含我们转储的类。
我们可以通过在Composer.json:中设置optimize-autoloader
配置指令,将Composer配置为始终优化自动加载器
"config": {
"optimize-autoloader": true
}
其应当为该项目修复CCD_ 23和CCD_。要解决非标准的名称空间问题有点麻烦。使用这种方法,请记住,每当我们在开发中添加一个不遵循PSR-4的新文件时,我们都需要转储自动加载器。
这似乎与Composer PSR自动加载有关。默认情况下,Laravel将包括
"autoload": {
"psr-4": {
"App\": "app/"
}
}
这意味着"App
命名空间的根在app
文件夹中,并且从那里匹配命名空间到文件夹结构"。
您的Saveeo
命名空间尚未注册(它不在App
层次结构中),因此Composer不知道它的位置。
如果您在composer.json(然后是dump-autoload
)中添加另一行,它应该会起作用
"autoload": {
"psr-4": {
"App\": "app/",
"Saveeo\": "app/Saveeo"
}
}
或者,正如另一个答案所指出的,您可以将整个Saveeo
命名空间放置在App
中(例如,它就是AppSaveeoBoardObserversEventsBoardHasBeenCreated
)。然而,Saveeo
命名空间似乎是一个自包含的模块,将其作为一个单独的命名空间可能更合理,而不是在其所有文件中重命名命名空间。
我相信如果您只是将名称空间更改为:
AppSaveeoBoardObservers
代替SaveeoBoardObservers
你所有的问题都应该解决。如果您有创建这个新名称空间的原因,而不是从基本的App名称空间分支出来,请告诉我。