2014-09-11 5 views
9

Ich habe versucht herauszufinden, was der Unterschied zwischen app->bind und app->singleton bei der Einrichtung eines Dienstleisters in Laravel sind. Ich hatte den Eindruck, dass, wenn ich ein singleton registriere, es die gleiche Instanz des Objekts jedes Mal zurückgeben würde, wenn es vs bind aufgerufen wurde, was eine neue Instanz wäre. HierLaravel Difference `zwischen app-> bind` und` app-> singleton`?

ist einfaches Beispiel:

Fassade:

use Illuminate\Support\Facades\Facade; 

class DataFacade extends Facade 
{ 
    protected static function getFacadeAccessor() { 
     return 'Data'; 
    } 
} 

Serviceprovider:

use Illuminate\Support\ServiceProvider; 

class DataServiceProvider extends ServiceProvider 
{ 
    public function register() { 
     $this->app->singleton('Data', function() { 
      return new Data; 
     }); 
    } 
} 

Klasse:

class Data 
{ 
    public $data = []; 

    public function get($key) 
    { 
     return isset($this->data[$key]) ? $this->data[$key] : null; 
    } 

    public function set($key, $val) 
    { 
     $this->data[$key] = $val; 
    } 
} 

Wenn wir so etwas wie:

$instance = App::make('Data'); 
$instance->set('foo', 'foo'); 

$instance2 = App::make('Data'); 

echo $instance->get('foo'); 
echo $instance2->get('foo'); 

und führt, dass wir das richtige Verhalten zwischen bind und singleton mit foo wird einmal ausgedruckt und dann jeweils zweimal sehen. Aber wenn wir es durch die Fassade laufen wie folgt:

Data::set('test', 'test'); 
Data::set('cheese', 'cheese'); 

Wenn es ein Singletons würde ich beide test und cheese erwarten verfügbar zu sein, und wenn es ein bind ist Ich bin nicht sicher, was ich erwarten würde über zur Verfügung stehen die Fassade, aber es scheint, als gäbe es keinen Unterschied.

Es ist die Fassade, die alles als singleton behandelt?

+0

Sie kennen den Unterschied bereits! –

+0

Du hast 'bind' erwähnt - aber deine Frage ruft nie direkt an bind. –

+0

Aber ruft die Fassade nicht den Dienstanbieter an, der Anrufe bindet? – Rob

Antwort

21

Ihre Frage ist ein wenig verwirrend und hat nicht alle Informationen, die jemand beantworten kann, aber es ist ein verwirrendes Thema, also fühlen Sie sich nicht schlecht. Hier ist ein Überblick, die Sie besser zu verstehen, und die Frage stellen Sie wollte fragen, ist (auch, ich bin ziemlich neu zu Laravel, so dass ich kann weg von der Unterseite mit diesen)

  1. Die make Verfahren verwendet wird, kann dazu beitragen, Objekte instanziieren. Wenn Sie App::make('Data') sagen, sagen Sie Laravel, ein Objekt aus der Klasse Data instanziieren.

  2. Es gibt eine Einschränkung 1. nummerieren Wenn Sie make nennen und gebunden haben bereits die Zeichenfolge Data auf etwas in der Service-Container, Laravel den Dienst stattdessen zurück.Dies kann bedeuten, Laravel ein neues Service-Objekt instanziiert, oder es kann bedeuten, Laravel gibt einen Service Singletons

  3. Unabhängig davon, ob Laravel einen Singleton zurückgibt oder eine Instanz für einen Dienst hängt von , wie der Dienst wurde gebunden

  4. die make Methode binden nicht alles

  5. Sie binden Dienste mit der bind Methode des Anwendungsobjekt, definiert auf der Container-Klasse mit der folgenden Methode Prototyp public function bind($abstract, $concrete = null, $shared = false)

  6. Sehen Sie das dritte $shared Parameter? Wenn das stimmt, gibt Ihr Dienst einen Singleton zurück. Wenn es falsch ist, wird Ihr Dienst Instanzen zurückgeben.

  7. Das singleton Methode der Anwendung Ziel ist ein Verfahren zum Binden von Dienstleistungen

Re: # 7, hier ist die Definition von singleton

#File: vendor/laravel/framework/src/Illuminate/Container/Container.php 
public function singleton($abstract, $concrete = null) 
{ 
    $this->bind($abstract, $concrete, true); 
} 

In Ihren obigen Beispielen Sie verbindlich der Service Data in den Container. Die Verwendung eines führenden Service-Namens führt zu Problemen - data wäre eine bessere Wahl. Wenn Ihre register Methode aus irgendeinem Grunde nicht genannt wird, make wird noch ein Objekt mit Ihrer globalen Klasse instanziiert Data

In Bezug auf Ihrer Fassade - eine Fassade ist eine zusätzliche Schicht von instance/Singleton-ness. Hier ist das Verfahren, bei dem die Fassadenklasse der Zeichenfolge getFacadeAccessor verwendet ein Objekt aus einem statischen Aufruf

#File: vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php 
protected static function resolveFacadeInstance($name) 
{ 
    if (is_object($name)) return $name; 

    if (isset(static::$resolvedInstance[$name])) 
    { 
     return static::$resolvedInstance[$name]; 
    } 

    return static::$resolvedInstance[$name] = static::$app[$name]; 
} 

So zurückzukehren, eine Fassade verwendet $app[$name]; einen Dienst aus dem Behälter zu greifen. Dies ist ArrayAccess, so dass, wenn wir bei der Definition aussehen von offsetGet

public function offsetGet($key) 
{ 
    return $this->make($key); 
} 

Wir sehen ArrayAccess einen Aufruf an make wickelt. Das bedeutet, wenn Sie keinen gebundenen Service haben, wird der Zugriff auf die Fassade ein Objekt instanziieren. Wenn der Dienst als Singleton/Shared Service gebunden ist, gibt der Fassadenzugriff diesen Singleton zurück. Wenn der Dienst als kein Singleton/Shared Service gebunden ist, wird durch den Zugriff auf die Fassade ein neues Objekt instanziiert.

JEDOCH, die Fassade selbst wird jedes Objekt speichern, das sie innerhalb static::$resolvedInstance instanziiert, und zukünftige Aufrufe an die Fassade werden dieselbe Instanz zurückgeben. Dies bedeutet, dass mit Facade Access eine zweite Singleton-Implementierung eingeführt wird. Ein Dienst, der als Singleton gebunden ist, wird im Anwendungsobjekt gespeichert. Ein Dienst, auf den über eine Fassade zugegriffen wird, wird als Singleton in der Klasse Facade gespeichert.

+1

Danke für diese großartige Erklärung, die hilft, Dinge viel zu klären. Mir fehlte das Stück über den Singleton an der Fassade. Wenn ich das richtig verstehe, beziehe ich mich auf mein Beispiel oben. Wenn also eine Fassade eine neue Instanz erstellt, wird es ein Singleton, der immer nur auf $ instance1 verweist, das er über die IoC/Service Provider-Bindung erstellt. Bedeutet das, dass eine Fassade immer als Singleton agiert, unabhängig davon, ob Ihr Dienstanbieter als neue Instanz/Singleton eingerichtet ist? Wenn ja, gibt es einen Weg um eine Fassade zu benutzen? Ich sollte hinzufügen, gibt es ein Szenario, wo wir wollen? – Rob

+1

@Rob - Ich bin noch weit von einem Experten entfernt, aber ja, es sieht so aus, als würde eine Fassade ein Objekt einmal instanziieren und dann immer das gleiche Objekt für Methodenaufrufe verwenden ** unabhängig davon, wie der Container gebunden ist . Sie können dies mit einer Servicemethode testen, die ein 'return $ this 'ausführt, die Methode über eine Fassade aufrufen und dann Statusüberprüfungen durchführen. Mein Verdacht ist dies war/ist eine bewusste Entscheidung zu Leistungsproblemen zu vermeiden mit "Dienstleistungen sind Instanzen nicht Singletons standardmäßig" –

+0

Ich denke, Fassaden machen hier Verwirrung, sie zwingen immer Singleton statt mehrerer Instanzen, auch wenn Sie mit geteilten Falsch binden. – Vedmant

Verwandte Themen