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

2022-08-30 08:46:36

我对laravel在IOC容器和立面方面提供的所有好东西感到有点困惑。由于我不是一个有经验的程序员,所以学习起来会变得势不可挡。

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

  1. “Foo”的立面,并通过以下方式在容器中注册App::bind()

  2. “Foo”的立面,并通过以下方式在容器中注册App::singleton()

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

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


答案 1

事实也正是如此。

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

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

结果如预期:

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,与第三个参数设置为 true 相同。Container::singletonContainer::bind


答案 2

立面确实作为单例工作,即使基础绑定不是单例。

假设您有:

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

和:

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

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

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

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

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

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


但有一个例外。大多数情况下,定义返回一个字符串,如上所示,但它也可以返回一个对象。立面示例:getFacadeAccessor()Schema

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

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

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


推荐