Laravel:区别 App::bind 和 App::singleton

新手上路,请多包涵

我对 laravel 在 IOC 容器和外观方面必须提供的所有好东西感到有点困惑。由于我不是经验丰富的程序员,因此学习起来会不知所措。

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

  1. “Foo”的门面并通过 App::bind() 在容器中注册

  2. “Foo”的外观并通过 App::singleton() 在容器中注册

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

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

原文由 Luuk Van Dongen 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 662
2 个回答

就是这样。

一个非常简单的证明是测试行为。由于 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";

结果符合预期:

Bind: test vs. test2

Singleton: test2 vs. test2

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

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

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

顺便说一句, Container::singletonContainer::bind 相同,第三个参数设置为true。

原文由 niclasleonbock 发布,翻译遵循 CC BY-SA 4.0 许可协议

Facades 确实像单例一样工作,即使底层绑定不是单例。

假设您有:

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

和:

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

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

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

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

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

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

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

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

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

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

原文由 Gras Double 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏