container bindings app php oop laravel-4 ioc-container facade

php - bindings - laravel singleton



Laravel: Difference App:: bind y App:: singleton (3)

Me confundo un poco con todas las cosas buenas que laravel tiene para ofrecer en términos del contenedor y las fachadas del COI. Como no soy un programador experimentado, es abrumador aprender.

Me preguntaba, ¿cuál es la diferencia entre estos dos ejemplos?

  1. Una fachada a ''Foo'' y registrada en el contenedor a través de App::bind()

  2. Una fachada para ''Foo'' y registrada en el contenedor a través de App::singleton()

En mi mejor entendimiento, Foo::method() se reescribirá como $app->make[''foo'']->method() así que en el primer ejemplo se crearán múltiples instancias de la clase Foo y en el segundo ejemplo, desde está vinculado a través de una App::singleton() , la misma instancia de Foo se devolverá cada vez que se llame a un método en ese objeto.

Lo siento si la respuesta a esta pregunta es obvia, pero no puedo encontrar ninguna confirmación sobre este asunto y en ninguna parte esto se explica claramente.


¿Pero en algún lugar leí que Laravel trata las clases llamadas a través de fachadas siempre como singletons?

Por lo tanto, me encontré con este problema:

Tengo una clase de demostración normalmente enlazada

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

Una configuración de una fachada

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

La clase en sí se ve así

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

Me dijiste que si usaba una fachada en esta clase, crearía una instancia de un objeto de la clase y luego llamaría al método sobre ese objeto.

Pero probé un poco más y encontré este comportamiento muy extraño (al menos para mí):

Si lo hago

Demo::setVal1(''13654''); y

Demo::setVal2(''random string'')

No debería poder usar Demo :: getVals () para recuperar los valores que acabo de crear, ¿o sí? Dado que cada vez que se utiliza un método de fachada se creará una instancia de un nuevo objeto y cómo un objeto puede recuperar propiedades de otro objeto. Debería haber tres instancias diferentes, pero aún así puedo recuperar las propiedades de esas otras instancias ...


Es exactamente así.

Una prueba muy simple es probar el bevahior. Como la aplicación Laravel simplemente extiende Illuminate/Container/Container , usaremos solo el contenedor (en mi caso, incluso agregué el contenedor como dependencia de mi composer.json) para probar.

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

El resultado es el esperado:

Bind: test vs. test2

Singleton: test2 vs. test2

Puede ser una prueba sucia, pero de hecho es una.

Toda la magia se encuentra en el método Container::make . Si el enlace se registra como compartido (lo que significa como singleton), se devuelve la instancia de clase, de lo contrario, una nueva instancia cada vez.

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

BTW, Container::singleton es lo mismo que Container::bind con el tercer parámetro establecido en true.


Las fachadas funcionan como singleton, incluso si el enlace subyacente no es un singleton.

Digamos que tienes:

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

y:

class Foo extends /Illuminate/Support/Facades/Facade { protected static function getFacadeAccessor() { return ''foo''; } }

Entonces esto creará 2 instancias de FooConcrete , como de costumbre:

app(''foo''); app(''foo'');

Pero esto creará solo una instancia de FooConcrete y la reutilizará:

Foo::someMethod(); Foo::someMethod();

Es porque resolveFacadeInstance() almacena las instancias resueltas.


Sin embargo, hay una excepción. La mayoría de las veces el getFacadeAccessor() definido devuelve una cadena , como se muestra arriba, pero también puede devolver un objeto . Ejemplo de la fachada de Schema :

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

En tal caso, resolveFacadeInstance() no almacena la instancia.

Entonces, si getFacadeAccessor() devuelve una nueva instancia, cada llamada a Facade también crea una nueva instancia.