web-dev-qa-db-ja.com

Laravel:違いApp :: bindとApp :: singleton

私はすてきなことすべてについて少し混乱しますlaravel IOCコンテナーとファサード。私は経験豊富なプログラマーではないので、学ぶのに圧倒されます。

これらの2つの例の違いは何ですか?

  1. 'Foo'へのファサードで、App::bind()を介してコンテナに登録されています

  2. 'Foo'へのファサードで、App::singleton()を介してコンテナに登録されています

Foo::method()$app->make['foo']->method()に書き換えられるので、最初の例ではFooクラスの複数のインスタンスが作成され、2番目の例ではバインドされているため、 App::singleton()を介して、そのオブジェクトのMethodが呼び出されるたびにFooの同じインスタンスが返されます。

この質問への答えが自明である場合は申し訳ありませんが、この問題に関する確認を見つけることができず、どこでもこれが明確に説明されていません。

59
Luuk Van Dongen

まさにそのようなものです。

非常に簡単な証拠は、bevahiorをテストすることです。 Laravelアプリケーションは単にIlluminate\Container\Containerを拡張する]であるため、コンテナーのみを使用し(私の場合は、composer.jsonへの依存関係としてのみコンテナーを追加します)、テストします。

require __DIR__ . '/vendor/autoload.php';

class FirstClass
{
    public $value;
}

class SecondClass
{
    public $value;
}

// Test bind()
$container = new Illuminate\Container\Container();

$container->bind('FirstClass');

$instance = $container->make('FirstClass');
$instance->value = 'test';

$instance2 = $container->make('FirstClass');
$instance2->value = 'test2';

echo "Bind: $instance->value vs. $instance2->value\n";

// Test singleton()
$container->singleton('SecondClass');

$instance = $container->make('SecondClass');
$instance->value = 'test';

$instance2 = $container->make('SecondClass');
$instance2->value = 'test2'; // <--- also changes $instance->value

echo "Singleton: $instance->value vs. $instance2->value\n";

結果は期待どおりです。

Bind: test vs. test2

Singleton: test2 vs. test2

汚い証拠かもしれませんが、確かにそれは一つです。

すべての魔法はContainer::makeメソッドにあります。バインディングが共有(つまりシングルトン)として登録されている場合、クラスインスタンスが返され、そうでない場合は毎回新しいインスタンスが返されます。

ソース: https://github.com/laravel/framework/blob/4.2/src/Illuminate/Container/Container.php#L442

ところで、Container::singletonは、3番目のパラメーターをtrueに設定したContainer::bindと同じです。

65
niclasleonbock

基礎となるバインディングがシングルトンでない場合でも、ファサードはシングルトンとして機能します。

あなたが持っているとしましょう:

_$app->bind('foo', 'FooConcrete'); // not a singleton
_

そして:

_class Foo extends \Illuminate\Support\Facades\Facade {
    protected static function getFacadeAccessor() { return 'foo'; }
}
_

次に、これにより、通常どおりFooConcreteの2つのインスタンスが作成されます。

_app('foo');
app('foo');
_

ただし、これによりFooConcreteのインスタンスが1つだけ作成され、再利用されます。

_Foo::someMethod();
Foo::someMethod();
_

resolveFacadeInstance() が解決されたインスタンスを保存するためです。


ただし、例外があります。ほとんどの場合、定義されたgetFacadeAccessor()は上記のようにstringを返しますが、オブジェクトSchema Facadeの例:

_protected static function getFacadeAccessor() {
    return static::$app['db']->connection()->getSchemaBuilder();
}
_

このような場合、resolveFacadeInstance()はインスタンスを保存しません。

したがって、getFacadeAccessor()が新しいインスタンスを返す場合、Facadeを呼び出すたびに新しいインスタンスも作成されます。

14
Gras Double

しかし、どこかで読んだLaravel=は、ファサードを介して呼び出されたクラスを常にシングルトンとして扱いますか?

それにより、私はこの問題に遭遇しました:

私は通常経由でバインドされたデモクラスを持っています

$ this-> app-> bind( 'demo'、function(){return new Demo();}

ファサードの設置

protected static function getFacadeAccessor(){return 'demo'; }

クラス自体は次のようになります

class Demo 
 {
 
 private $ value1; 
 private $ value2; 
 
 public function setVal1($ value)
 {
 $ this-> value1 = $ value; 
} 
 
 public function setVal2($ value)
 {
 $ this-> value2 = $ value; 
} 
 
 public function getVals( )
 {
 return 'Val 1:'。 $ this-> value1。 「Val 2:」 $ this-> value2; 
} 
 
}

このクラスでファサードを使用すると、クラスのオブジェクトがインスタンス化され、そのオブジェクトでメソッドが呼び出されると言われました。

しかし、私はさらにいくつかをテストし、この非常に奇妙な(少なくとも私には)動作を発見しました:

私が行った場合

Demo :: setVal1( '13654');
Demo :: setVal2( 'random string')

Demo :: getVals()を使用して、作成した値を取得することはできません。ファサードメソッドが使用されるたびに、新しいオブジェクトがインスタンス化されるので、あるオブジェクトが別のオブジェクトのプロパティを取得する方法を教えてください。 3つの異なるインスタンスがあるはずですが、それでも他のインスタンスからプロパティを取得できます...

3
Luuk Van Dongen