Laravel: Différence App::bind et App::singleton
je suis un peu confus sur toutes les belles choses que laravel a à offrir en termes de conteneur et de façades de L'IOC. Comme je ne suis pas un programmeur expérimenté, il devient accablant d'apprendre.
je me demandais, quelle est la différence entre ces deux exemples:
Une façade 'Foo' et inscrit dans le conteneur à l'aide de
App::bind()
une façade à "Foo" et enregistré dans le conteneur via
App::singleton()
Dans mon meilleur compréhension Foo::method()
sera réécrit comme $app->make['foo']->method()
donc dans le premier exemple plusieurs instances du Foo
la classe sera créée et dans le second exemple, puisqu'elle est liée par un App::singleton()
, la même instance de Foo
sera retourné chaque fois qu'une méthode sur cet objet est appelée.
je suis désolé si la réponse à cette question est trop évidente, mais je ne trouve aucune confirmation à ce sujet et nulle part ceci n'est clairement expliquer.
3 réponses
C'est exactement comme ça.
une preuve très simple est de tester le bevahior. Depuis L'Application Laravel étend simplement Illuminate\Container\Container
, nous n'utiliserons que le container (dans mon cas j'ai même ajouté le container comme dépendance à mon compositeur.json) pour tester.
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";
Le résultat est comme prévu:
Bind: test vs. test2
Singleton: test2 vs. test2
C'est peut-être une preuve sale, mais en fait c'en est une.
Toute la magie réside dans le Container::make
méthode.
Si la liaison est enregistrée comme partagée (ce qui signifie Comme singleton), l'instance de classe est retournée, sinon une nouvelle instance à chaque fois.
Source: https://github.com/laravel/framework/blob/4.2/src/Illuminate/Container/Container.php#L442
BTW,Container::singleton
est le même que Container::bind
avec le troisième paramètre défini à true.
les façades fonctionnent comme un singleton, même si la reliure sous-jacente n'est pas un singleton.
disons que vous avez:
$app->bind('foo', 'FooConcrete'); // not a singleton
et:
class Foo extends \Illuminate\Support\Facades\Facade {
protected static function getFacadeAccessor() { return 'foo'; }
}
Ensuite, cela permettra de créer 2 instances de FooConcrete
, comme d'habitude:
app('foo');
app('foo');
mais cela ne créera qu'une seule instance de FooConcrete
et le réutiliser:
Foo::someMethod();
Foo::someMethod();
C'est parce que resolveFacadeInstance()
stocke les instances résolues.
Il y a un exception cependant. La plupart du temps, la définition de getFacadeAccessor()
retourne un chaîne, comme montré ci-dessus, mais il peut aussi retourner un objet. Exemple de l' Schema
Façade:
protected static function getFacadeAccessor() {
return static::$app['db']->connection()->getSchemaBuilder();
}
dans un tel cas,resolveFacadeInstance()
ne stocke pas l'instance.
si getFacadeAccessor()
retourne une nouvelle instance, chaque appel à la Façade crée une nouvelle instance.
mais quelque part J'ai lu que Laravel traite les classes appelées via façades toujours comme des Singleton?
J'ai donc rencontré ce problème:
j'ai un démo classe normalement lié par
$this->app->bind('demo', function() { return new Demo(); }
un montage une façade
protected static function getFacadeAccessor() { return 'demo'; }
La classe elle-même ressemble à ceci
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; } }
Vous m'avez dit que si je voulais utiliser une façade sur cette classe, instancier un objet de la classe, puis d'appeler la méthode sur cette objet.
Crosse je l'ai testé et trouvé cela très étrange (au moins pour moi) comportement:
Si je fais
Demo::setVal1('13654');et
Demo::setVal2('random string')
Je ne devrais pas pouvoir utiliser Demo::getVals() pour récupérer les valeurs que je viens de créer, devrais-je? Depuis chaque fois qu'une méthode de façade est utilisée, un nouvel objet sera instancié et comment un objet peut-il récupérer les propriétés d'un autre objet? Il devrait y avoir trois instances différentes mais je suis quand même capable de récupérer les propriétés de ces d'autres instances...