Laravel: Difference App::bind and App::singleton



我对laravel在IOC容器和外观方面提供的所有好东西感到有点困惑。因为我不是一个有经验的程序员,所以学习起来很难。

我想知道,这两个例子有什么不同:

  1. 'Foo'的facade并通过App::bind()

  2. 在容器中注册
  3. 'Foo'的facade并通过App::singleton()在容器中注册

在我最好的理解中,Foo::method()将被重写为$app->make['foo']->method(),因此在第一个示例中将创建Foo类的多个实例,在第二个示例中,由于它是通过App::singleton()绑定的,因此每次调用该对象上的方法时都会返回Foo的相同实例。

如果这个问题的答案是显而易见的,我很抱歉,但我找不到任何关于这件事的确认,也没有任何地方对此有明确的解释。

就是这样。

一个非常简单的证明是测试行为。由于Laravel应用程序只是简单地扩展了IlluminateContainerContainer,我们将只使用容器(在我的情况下,我甚至只将容器作为依赖项添加到我的composer.json中)来测试。

require __DIR__ . '/vendor/autoload.php';
class FirstClass
{
    public $value;
}
class SecondClass
{
    public $value;
}
// Test bind()
$container = new IlluminateContainerContainer();
$container->bind('FirstClass');
$instance = $container->make('FirstClass');
$instance->value = 'test';
$instance2 = $container->make('FirstClass');
$instance2->value = 'test2';
echo "Bind: $instance->value vs. $instance2->valuen";
// 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->valuen";

结果如预期:

Bind: test vs. test2

Singleton: test2 vs. test2

可能是一个肮脏的证明,但它确实是一个。

所有的魔力都在于Container::make方法。如果绑定被注册为共享(这意味着作为单例),则返回类实例,否则每次都返回一个新实例。

来源:https://github.com/laravel/framework/blob/4.2/src/Illuminate/Container/Container.php L442

BTW, Container::singletonContainer::bind相同,第三个参数设置为true

facade作为单例工作,即使底层绑定不是单例。

假设你有:

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

:

class Foo extends IlluminateSupportFacadesFacade {
    protected static function getFacadeAccessor() { return 'foo'; }
}
然后这将创建2个FooConcrete实例,像往常一样:
app('foo');
app('foo');

但是这将只创建一个FooConcrete实例并重用它:

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

这是因为resolveFacadeInstance()存储了解析的实例。


不过也有例外。大多数情况下,定义的getFacadeAccessor()返回字符串,如上所示,但它也可以返回对象Schema Facade的例子:

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

在这种情况下,resolveFacadeInstance()不存储实例。

因此,如果getFacadeAccessor()返回一个新实例,那么对Facade的每次调用也会创建一个新实例。

但是我在某个地方读到Laravel将通过facade调用的类始终视为单例?

因此,我遇到了这样的问题:

我有一个演示类通常通过 绑定
$this->app->bind('demo', function(){返回新的demo ();} 之前

设置门面

受保护静态函数getFacadeAccessor(){返回'demo';} 之前

类本身看起来像这样

<>以前课堂演示{私人value1美元;私人value2美元;setVal1($value){$this->value1 = $value;}setVal2($value){$this->value2 = $value;}getVals(){返回'Val 1: '。$this->value1 . 'Val 2: '。$ this -> value2;}} 之前

你告诉我,如果我在这个类上使用facade,它将实例化类的一个对象,然后调用该对象的方法。

但我测试了更多,发现这个非常奇怪(至少对我来说)的行为:

<>之前如果我做演示::setVal1("13654");

和<>之前演示::setVal2(随机字符串)之前

我不应该能够使用Demo::getVals()来检索我刚刚创建的值,应该吗?因为每次使用facade方法时都会实例化一个新对象,一个对象如何检索另一个对象的属性?应该有三个不同的实例但我仍然可以从其他实例中检索属性。

最新更新