2016-09-23 9 views
2

と呼ばれていない私は、次の定義があります。Laravel繰延サービスプロバイダ `provides`が

namespace App\Providers; 

use Illuminate\Support\ServiceProvider; 
use App\SomeClass; 

class SomeProvider extends ServiceProvider 
{ 
    protected $defer = true; 

    public function register() 
    { 
     $this->app->bind(SomeClass::class, function ($app) 
     { 
      return new SomeClass(); 
     }); 
    } 

    public function provides() 
    { 
     die("This never gets called"); 
     return [SomeClass::class]; 
    } 
} 

をそして期待通り$deferが、その後provides()真である場合には、それはマニュアルに従って除き、SomeClassのインスタンスを返します。メソッドを呼び出す必要があります。私が実際にSomeClassのインスタンスを要求するかどうかに関係なく、$deferを設定しても、provides()は呼び出されません。

次のように私はクラスのインスタンスを求めてるの方法は次のとおりです。

App::make('SomeClass'); 
+0

プロバイダーをプロバイダアレイに 'config/app.php'で登録しましたか? – user3158900

+0

@ user3158900はい。私はそれが適切に延期されているとは思わないので、provide()が呼び出されない限り、プロバイダは正常に動作します。 – Julian

+0

Laravelのコンテナは実際にサービスプロバイダに登録されていないクラスのインスタンスを実際に作成できるため、したがって、Laravelがサービスプロバイダーについて知らない場合、それを延期する必要はないと考えられます。 – user3158900

答えて

3

短い答え:
あなたのコンパイルしたマニフェストファイルがすでにフレームワークによってコンパイルされています。それは名前のキャッシュされたファイルに書き込みLaravelはアプリケーションをビルドする(とのIoCにサービスプロバイダのすべてを解決します)初めて で

services.php(つまり、マニフェストファイルに置か: bootstrap/cache/services.php)。
php artisan clear-compiledでコンパイルしたコマンドをクリアすると、フレームワークがマニフェストファイルを再構築するようになり、 providesメソッドが呼び出されることに注意してください。 次の呼び出し/要求では、 providesメソッドはもはや呼び出されません。

フレームワークブーツの順序は、ほぼこのようなものです:ブートストラッパの

//public/index.php 
$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../') 
); 

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 
    \Illuminate\Foundation\Http\Kernel::__construct(); 
    \Illuminate\Foundation\Http\Kernel::handle(); 
     \Illuminate\Foundation\Http\Kernel::sendRequestThroughRouter(); 
      \Illuminate\Foundation\Http\Kernel::bootstrap(); 
       \Illuminate\Foundation\Application::bootstrapWith(); 
        # where $bootstrapper is a item from \Illuminate\Foundation\Http\Kernel::$bootstrappers 
        # and $this is instance of \Illuminate\Foundation\Application 
        \Illuminate\Foundation\Application::make($bootstrapper)->bootstrap($this); 

一つは は\Illuminate\Foundation\Application::registerConfiguredProviders()を呼び出しIlluminate\Foundation\Bootstrap\RegisterProvidersで、最終的に \Illuminate\Foundation\ProviderRepository::__construct()と呼び出し:

\Illuminate\Foundation\ProviderRepository::load()

\Illuminate\Foundation\ProviderRepository::load()がありますすべてのサービスプロバイダと呼ばれる、登録されている \Illuminate\Support\ServiceProvider::provides()もよく呼び出されます。ここ

そして、あなたは(\Illuminate\Foundation\ProviderRepository::loadから)知っておくべき抜粋です。

/** 
    * Register the application service providers. 
    * 
    * @param array $providers 
    * @return void 
    */ 
    public function load(array $providers) 
    { 
     $manifest = $this->loadManifest(); 

     // First we will load the service manifest, which contains information on all 
     // service providers registered with the application and which services it 
     // provides. This is used to know which services are "deferred" loaders. 
     if ($this->shouldRecompile($manifest, $providers)) { 
      $manifest = $this->compileManifest($providers); 
     } 

     // Next, we will register events to load the providers for each of the events 
     // that it has requested. This allows the service provider to defer itself 
     // while still getting automatically loaded when a certain event occurs. 
     foreach ($manifest['when'] as $provider => $events) { 
      $this->registerLoadEvents($provider, $events); 
     } 

     // We will go ahead and register all of the eagerly loaded providers with the 
     // application so their services can be registered with the application as 
     // a provided service. Then we will set the deferred service list on it. 
     foreach ($manifest['eager'] as $provider) { 
      $this->app->register($this->createProvider($provider)); 
     } 

     $this->app->addDeferredServices($manifest['deferred']); 
    } 

\Illuminate\Foundation\ProviderRepository::compileManifest()あなたprovides()メソッドが実行される場所です。

+0

非常に詳細な情報をありがとう。私はデバッガを使いこなしていたので、あなたの説明のおかげで何が起こっているのかもっと理解できるようになりました。 – Julian

0

私自身のテストをした後、これが問題であるように見えます(この場合は、「問題」が強いかもしれません)。

クラスの名前を持つサービスプロバイダに何かを登録すると、Laravelはそのクラスを返し、サービスプロバイダにあるものは無視します。私はあなたがやったのと同じことをやって始めた....

protected $defer = true; 

public function register() 
{ 
    $this->app->bind(SomeClass::class, function ($app) 
    { 
     return new SomeClass(); 
    }); 
} 

public function provides() 
{ 
    dd('testerino'); 
} 

$test = \App::make('App\SomeClass'); 

そして$testSomeClassのインスタンスです。しかし、私は次の変更を加える...

$this->app->bind('test', function ($app) { ... } 

し、それがdeffered機能を打つと、テキストtesterinoを出力

$test = \App::make('test'); 

を使用しています。

ここでの問題は、Laravelがクラスを取得しようとしていることを知っていることです。この例では、コンテナに登録しようとしているものを登録する必要はなく、App\SomeClassのインスタンスを作成するときに、LaravelにApp\SomeClassというインスタンスを作成すること以外は何もしません。あなたはLaravelを伝える場合はApp::make('test')を呼び出すとき

は、しかし、あなたがApp\SomeClassのインスタンスをしたい、それは実際ので、私はそれがサービスプロバイダに注意を払うように開始さだと思いtestにそのクラスをバインドする必要があります。

関連する問題