为了让这更有趣,如果我运行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 Saveeo\Board\Observers\BoardEventListener does not exist
BoardEventListener.php (置于Saveeo / Board / Observers中)
<?php
namespace Saveeo\Board\Observers;
use Saveeo\Services\HashIds\Contracts\HashIds 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(
'Saveeo\Board\Observers\Events\BoardHasBeenCreated',
'Saveeo\Board\Observers\BoardEventListener@whenBoardIsCreated'
);
$events->listen(
'Saveeo\Board\Observers\Events\BoardHasBeenUpdated',
'Saveeo\Board\Observers\BoardEventListener@whenBoardIsUpdated'
);
}
}
EventServiceProvider.php (置于Saveeo / Providers中)
<?php
namespace Saveeo\Providers;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider 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 = [
'Saveeo\Board\Observers\BoardEventListener',
];
/**
* Register any other events for your application.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(DispatcherContract $events) {
parent::boot($events);
//
}
}
这是文件夹结构。这里看不出有什么问题?
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"
}
}
答案 0 :(得分:7)
我们似乎已将 app / 目录中的类从artisan app:name
(默认值)更改为{自动加载命名空间(手动或使用App
){ composer.json 中的{1}}:
Saveeo
当我们理解其含义时,完全很好。当我们看一下导致异常的文件的项目文件夹结构(括号中的命名空间)时,我们可以看到问题中描述的问题:
"autoload": {
"psr-4": {
"Saveeo\\": "app/"
}
},
为了与PSR-4兼容,app (Saveeo)
├── Saveeo (Saveeo\Saveeo)
│ ├── Board (Saveeo\Saveeo\Board)
│ │ ├── Observers (Saveeo\Saveeo\Board\Observers)
│ │ │ ├── BoardEventListener
└── ...
的命名空间应为BoardEventListener
,因为它存在于嵌套在 app / Saveeo / 目录中>。 PSR-4 autoloading实现基于文件名和路径,解析类文件而不是文件中声明的命名空间。 [Composer 从类文件中读取命名空间以创建优化的类映射,只要顶级命名空间匹配即可。见更新。]
如果我们不想更改应用程序的目录结构,并且我们也不想在命名空间中使用两个Saveeo\Saveeo\Board\Observers
,我们可以将Composer配置为在自动加载类时将两个目录合并到同一名称空间中:
Saveeo
...并记住"autoload": {
"psr-4": {
"Saveeo\\": [ "app/", "app/Saveeo/" ]
}
},
。
它有效,但我不建议在实践中使用它。它偏离了PSR-4标准,使应用程序容易受到名称空间冲突的影响,并且可能会使其他从事该项目的人感到困惑。我建议您展平composer dump-autoload
命名空间和目录,或者为嵌套目录中的类选择不同的命名空间。
...如果我运行
Saveeo
,事情就会正常工作但我很好奇为什么当我运行composer dump-autoload -o
时会出现错误?
生成自动加载缓存文件时,Composer实际上并不执行您的代码。但是,composer update
命令在大多数Laravel应用程序中运行artisan optimize
之后(直到5.5),会启动应用程序以执行其操作,因此问题代码会执行,我们看到例外。
<强>更新强>
如果使用
composer update
错误而不是Saveeo\Board\etc
,那么整个应用程序周围的其他文件将无效,但确实如此。
我们可以在生成优化自动加载器时,技术上使用与项目目录结构不匹配的非PSR-4命名空间,就像我们准备应用程序一样制作:
Saveeo\Saveeo\Board\etc
这是有效的,因为Composer将扫描每个类文件以查找名称空间以创建静态类图。当我们没有指定composer dump-autoload --optimize
时,Composer依赖于动态自动加载,它将文件路径与名称空间匹配,因此非标准名称空间或目录结构无法解析。
相关项目的命名空间大部分都适用,即使它不遵循PSR-4,因为我们使用--optimize
-o
选项手动转储优化的自动加载器}。但是,我们看到错误消息,因为dump-autoload
在运行更新之前删除了缓存的类映射,因此,当composer update
命令运行时,类映射不再包含类我们抛弃了。
我们可以通过在 composer.json 中设置artisan optimize
配置指令,将Composer配置为always optimize the autoloader:
optimize-autoloader
...应修复此项目的"config": {
"optimize-autoloader": true
}
和install
命令。获得非标准命名空间来解决这个问题有点麻烦。使用这种方法,请记住,每当我们在开发中添加不遵循PSR-4的新文件时,我们都需要转储自动加载器。
答案 1 :(得分:6)
这似乎与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
内(例如,App\Saveeo\Board\Observers\Events\BoardHasBeenCreated
)。但是,您的Saveeo
命名空间似乎是一种自包含的模块,将它作为单独的命名空间而不是在其所有文件中重命名命名空间可能更合理。
答案 2 :(得分:3)
我相信如果您只是将名称空间更改为:
App\Saveeo\Board\Observers
代替Saveeo\Board\Observers
所有问题都应该解决。如果您有理由创建这个新的命名空间,请告诉我,而不是仅仅从基本的 App 命名空间扩展出来。