Laravel:差异App :: bind和App :: singleton

Luu*_*gen 62 php oop facade ioc-container laravel-4

我对laravel在IOC容器和外墙方面提供的所有好东西感到有些困惑.由于我不是一位经验丰富的程序员,因此学习起来势不可挡.

我想知道,这两个例子有什么区别:

  1. 'Foo'的门面并通过容器注册 App::bind()

  2. 'Foo'的门面并通过容器注册 App::singleton()

在我的最佳理解Foo::method()中将被重写,$app->make['foo']->method()因为在第一个示例Foo中将创建类的多个实例,并且在第二个示例中,因为它通过a绑定App::singleton(),所以Foo每次调用该对象上的Method时都将返回相同的实例.

如果这个问题的答案显而易见,我很抱歉,但我找不到任何关于这个问题的确认,也没有明确解释.

小智 69

就是这样.

一个非常简单的证据是测试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";
Run Code Online (Sandbox Code Playgroud)

结果如预期:

Bind: test vs. test2

Singleton: test2 vs. test2

可能是一个肮脏的证据,但实际上它是一个.

所有的魔力都在于Container::make方法.如果绑定注册为shared(表示为singleton),则返回类实例,否则每次都返回一个新实例.

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

顺便说一句,Container::singleton是一样的Container::bind设置为true第三个参数.


Gra*_*ble 14

即使底层绑定不是单身,外墙也可以作为单身人士工作.

假设你有:

$app->bind('foo', 'FooConcrete'); // not a singleton
Run Code Online (Sandbox Code Playgroud)

和:

class Foo extends \Illuminate\Support\Facades\Facade {
    protected static function getFacadeAccessor() { return 'foo'; }
}
Run Code Online (Sandbox Code Playgroud)

然后这将FooConcrete像往常一样创建2个实例:

app('foo');
app('foo');
Run Code Online (Sandbox Code Playgroud)

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

Foo::someMethod();
Foo::someMethod();
Run Code Online (Sandbox Code Playgroud)

这是因为resolveFacadeInstance()存储已解析的实例.


但有一个例外.大多数情况下,define getFacadeAccessor()返回一个字符串,如上所示,但它也可以返回一个对象.SchemaFacade 示例:

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

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

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