php Laravel:区别 App::bind 和 App::singleton
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25229064/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Laravel: Difference App::bind and App::singleton
提问by Luuk Van Dongen
I get a bit confused over all the nice things laravel has to offer in terms of the IOC container and facades. Since I'm not an experienced programmer it gets overwhelming to learn.
我对 laravel 在 IOC 容器和外观方面提供的所有好东西感到有些困惑。因为我不是一个有经验的程序员,所以学习起来很困难。
I was wondering, what is the difference between these two examples:
我想知道,这两个例子有什么区别:
A facade to 'Foo' and registered in the container via
App::bind()
A facade to 'Foo' and registered in the container via
App::singleton()
'Foo' 的外观并通过以下方式在容器中注册
App::bind()
'Foo' 的外观并通过以下方式在容器中注册
App::singleton()
In my best understanding Foo::method()
will be rewritten as $app->make['foo']->method()
so in the first example multiple instances of the Foo
class will be created and in the second example, since it's bound via an App::singleton()
, the same instance of Foo
will be returned every time a Method on that object is called.
在我最好的理解Foo::method()
中将被重写,$app->make['foo']->method()
因为在第一个示例Foo
中将创建类的多个实例,而在第二个示例中,由于它是通过 绑定的App::singleton()
,因此Foo
每次调用该对象上的方法时都会返回相同的实例。
I'm sorry if the answer to this question is to obvious, but I can't find any confirmation on this matter and nowhere this is clearly explained.
如果这个问题的答案很明显,我很抱歉,但我找不到关于此事的任何确认,也没有任何地方对此进行明确解释。
回答by niclasleonbock
It's exactly like that.
就是这样。
A very simple proof is to test out the behavior. Since the Laravel Application simply extends Illuminate\Container\Container
, we'll use just the container (in my case I even only added the container as a dependency to my composer.json) to test.
一个非常简单的证明是测试行为。由于 Laravel 应用程序只是 extends 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";
The result is as expected:
结果如预期:
Bind: test vs. test2
Bind: test vs. test2
Singleton: test2 vs. test2
Singleton: test2 vs. test2
Might be a dirty proof, but indeed it is one.
可能是一个肮脏的证据,但确实是一个。
All the magic lies in the Container::make
method.
If the binding is registered as shared (which means as singleton), the class instance is returned, otherwise a new instance every time.
所有的魔法都在于Container::make
方法。如果绑定注册为共享(即单例),则返回类实例,否则每次都会返回一个新实例。
Source: https://github.com/laravel/framework/blob/4.2/src/Illuminate/Container/Container.php#L442
来源:https: //github.com/laravel/framework/blob/4.2/src/Illuminate/Container/Container.php#L442
BTW, Container::singleton
is the same as Container::bind
with the third parameter set to true.
顺便说一句,Container::singleton
是一样的Container::bind
设置为true第三个参数。
回答by Gras Double
Facades do work as singleton, even if the underlying binding is not a singleton.
Facades 确实作为单例工作,即使底层绑定不是单例。
Let's say you have:
假设你有:
$app->bind('foo', 'FooConcrete'); // not a singleton
and:
和:
class Foo extends \Illuminate\Support\Facades\Facade {
protected static function getFacadeAccessor() { return 'foo'; }
}
Then this will create 2 instances of FooConcrete
, as usual:
然后这将FooConcrete
像往常一样创建 2 个实例:
app('foo');
app('foo');
But this will create only one instance of FooConcrete
and reuse it:
但这只会创建一个实例FooConcrete
并重用它:
Foo::someMethod();
Foo::someMethod();
It is because resolveFacadeInstance()
stores the resolved instances.
这是因为resolveFacadeInstance()
存储解析的实例。
There is an exception though. Most of the time the defined getFacadeAccessor()
returns a string, as shown above, but it can also return an object. Example from the Schema
Facade:
不过也有例外。大多数情况下,定义getFacadeAccessor()
返回一个字符串,如上所示,但它也可以返回一个对象。Schema
Facade 中的示例:
protected static function getFacadeAccessor() {
return static::$app['db']->connection()->getSchemaBuilder();
}
In such a case, resolveFacadeInstance()
doesn't store the instance.
在这种情况下,resolveFacadeInstance()
不存储实例。
So if getFacadeAccessor()
returns a new instance, each call to the Facade creates a new instance as well.
因此,如果getFacadeAccessor()
返回一个新实例,则对 Facade 的每次调用也会创建一个新实例。
回答by Luuk Van Dongen
But somewhere I read that Laravel treats classes called via facades always as singletons?
但是在某处我读到 Laravel 将通过门面调用的类始终视为单例?
Thereby, I encountered this problem:
因此,我遇到了这个问题:
I have a demo class normally bound via
我有一个演示类通常通过
$this->app->bind('demo', function() { return new Demo(); }
An sett up a facade
一个立面
protected static function getFacadeAccessor() { return 'demo'; }
The class itself looks like this
类本身看起来像这样
class Demo { private $value1; private $value2; public function setVal1($value) { $this->value1 = $value; } public function setVal2($value) { $this->value2 = $value; } public function getVals() { return 'Val 1: ' . $this->value1 . ' Val 2: ' . $this->value2; } }
You told me that if I would use a facade on this class, it would instantiate an object of the class and then call the method on that object.
你告诉我,如果我在这个类上使用一个外观,它会实例化这个类的一个对象,然后调用那个对象上的方法。
Butt I tested some more and found this very strange (at least to me) behavior:
Butt 我测试了更多,发现这种非常奇怪(至少对我而言)的行为:
If I do
如果我做
Demo::setVal1('13654');和
Demo::setVal2('random string')
I shouldn't be able to use Demo::getVals() to retrieve the values I just created, should I? Since every time a facade method is used a new object will be instantiated and how can one object retrieve properties of another object? There should be three different instances but still I'm able to retrieve the properties from those other instances...
我不应该使用 Demo::getVals() 来检索我刚刚创建的值,对吗?由于每次使用外观方法时都会实例化一个新对象,一个对象如何检索另一个对象的属性?应该有三个不同的实例,但我仍然能够从其他实例中检索属性......