对于存在的文件,在composer update上抛出ReflectionException

Ali*_*ani 10 php laravel composer-php laravel-5

为了让这个更有趣,如果我跑的话,事情就可以了,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  
Run Code Online (Sandbox Code Playgroud)

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'
        );

    }
}
Run Code Online (Sandbox Code Playgroud)

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);

        //
    }
}
Run Code Online (Sandbox Code Playgroud)

这是文件夹结构.这里看不出有什么不对吗?

https://imgur.com/BI44Lq6

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"
    }
}
Run Code Online (Sandbox Code Playgroud)

Cy *_*nol 7

它看起来像我们改变了自动加载的命名空间(手动,或通过使用artisan app:name在类)应用程序/从目录App(默认值)Saveeocomposer.json:

"autoload": {
    "psr-4": {
        "Saveeo\\": "app/"
    }
},
Run Code Online (Sandbox Code Playgroud)

当我们理解其含义时,这是完全正常的.当我们查看导致异常的文件的项目文件夹结构(括号中的命名空间)时,我们可以看到问题中描述的问题:

app                    (Saveeo)
??? Saveeo             (Saveeo\Saveeo)
?   ??? Board          (Saveeo\Saveeo\Board)
?   ?   ??? Observers  (Saveeo\Saveeo\Board\Observers)
?   ?   ?   ??? BoardEventListener
??? ...
Run Code Online (Sandbox Code Playgroud)

为了与PSR-4兼容,名称空间BoardEventListener应该是Saveeo\Saveeo\Board\Observers因为它存在于嵌套在app /下的Saveeo /目录中.PSR-4自动加载基于实现解析类文件的文件名和路径,未声明的命名空间的文件.[ 只要顶级命名空间匹配,Composer就会从类文件读取命名空间以创建优化的类映射.见更新.]

如果我们不想更改应用程序的目录结构,并且我们不想Saveeo在命名空间中使用两个s,我们可以将Composer配置为在自动加载类时将两个目录合并到同一个命名空间中:

"autoload": {
    "psr-4": {
        "Saveeo\\": [ "app/", "app/Saveeo/" ]
    }
},
Run Code Online (Sandbox Code Playgroud)

......记住composer dump-autoload.

它有效,但我不建议在实践中使用它.它偏离了PSR-4标准,使应用程序容易受到名称空间冲突的影响,并且可能会使其他从事该项目的人感到困惑.我建议您展平Saveeo命名空间和目录,或者为嵌套目录中的类选择不同的命名空间.

...如果我跑的话,工作正常,composer dump-autoload -o但我很好奇为什么当我跑composer update... 时会抛出错误?

生成自动加载缓存文件时,Composer实际上并不执行您的代码.但是,在大多数Laravel应用程序(直到5.5)artisan optimize之后运行的命令会引导应用程序执行其操作,因此问题代码会执行,我们会看到异常.composer update

更新:

如果使用Saveeo\Board\etc是错误的,Saveeo\Saveeo\Board\etc那么整个应用程序周围的其他文件将无法正常工作,但确实如此.

当我们生成优化的自动加载器时,我们可以在技术上使用与项目目录结构不匹配的非PSR-4名称空间,就像我们为生产准备应用程序一样:

composer dump-autoload --optimize 
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为Composer将扫描每个类文件以查找名称空间以创建静态类映射.当我们不指定时--optimize,Composer依赖于动态自动加载,它将文件路径与名称空间匹配,因此非标准名称空间或目录结构无法解析.

有问题的项目的命名空间大部分都适用,即使它不遵循PSR-4,因为我们通过使用-o选项来手动转储优化的自动加载器dump-autoload.但是,我们看到错误消息,因为在运行更新之前composer update 删除了缓存的类映射,因此,在artisan optimize命令运行时,类映射不再包含我们转储的类.

我们可以将Composer配置为始终通过optimize-autoloadercomposer.json中设置配置指令来优化自动装带器:

"config": { 
    "optimize-autoloader": true 
}
Run Code Online (Sandbox Code Playgroud)

...应修复此项目的命令installupdate命令.获得非标准命名空间来解决这个问题有点麻烦.使用这种方法,请记住,每当我们在开发中添加不遵循PSR-4的新文件时,我们都需要转储自动加载器.


ale*_*ino 6

这似乎与Composer PSR自动加载有关.默认情况下,Laravel将包含

"autoload": {
    "psr-4": {
        "App\\": "app/"
    }
}
Run Code Online (Sandbox Code Playgroud)

这意味着" App命名空间的根目录在app文件夹中,并从那里匹配命名空间到文件夹结构".

您的Saveeo命名空间尚未注册(它不在App层次结构中),因此Composer不知道它的位置.

如果你在composer.json中添加另一行(然后dump-autoload)

"autoload": {
    "psr-4": {
        "App\\": "app/",
        "Saveeo\\": "app/Saveeo"
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以像其他答案所指出的那样,将整个Saveeo命名空间置于其中App(App\Saveeo\Board\Observers\Events\BoardHasBeenCreated例如,这样).但是,您的Saveeo命名空间似乎是一种自包含的模块,将它作为单独的命名空间而不是在其所有文件中重命名命名空间可能更合理.