问题描述
我一直在尝试找出在Laravel中设置服务提供者时app->bind
和app->singleton
之间的区别.我的印象是,如果我注册一个singleton
,则每次调用该对象时都会返回该对象的相同实例vs bind
,这将是一个新实例.
I've been trying to figure out what the difference between app->bind
and app->singleton
are when setting up a service provider in Laravel. I was under the impression that if I register an singleton
it would return the same instance of the object each time it was called vs bind
which would be a new instance.
这是一个简单的例子:
门面:
use Illuminate\Support\Facades\Facade;
class DataFacade extends Facade
{
protected static function getFacadeAccessor() {
return 'Data';
}
}
ServiceProvider:
ServiceProvider:
use Illuminate\Support\ServiceProvider;
class DataServiceProvider extends ServiceProvider
{
public function register() {
$this->app->singleton('Data', function() {
return new Data;
});
}
}
班级:
class Data
{
public $data = [];
public function get($key)
{
return isset($this->data[$key]) ? $this->data[$key] : null;
}
public function set($key, $val)
{
$this->data[$key] = $val;
}
}
如果我们做类似的事情:
If we do something like:
$instance = App::make('Data');
$instance->set('foo', 'foo');
$instance2 = App::make('Data');
echo $instance->get('foo');
echo $instance2->get('foo');
运行,我们将看到bind
和singleton
之间的适当行为,其中foo
分别打印了一次,然后打印了两次.但是,如果我们像这样通过立面运行它:
And run that we will see the appropriate behavior between bind
and singleton
with foo
being printed out once and then twice respectively. However if we run it through the facade like so:
Data::set('test', 'test');
Data::set('cheese', 'cheese');
当它是单例时,我希望test
和cheese
都可用,而当它是bind
时,我不确定我希望通过立面获得什么,但是似乎有没什么
When it's a singleton I would expect both test
and cheese
to be available and when it's a bind
I'm not sure what I would expect to be available via the facade, but it seems like there is no difference.
是将所有内容都视为singleton
的立面吗?
It's the facade treating everything as a singleton
?
推荐答案
您的问题有点令人困惑,并且没有人可以回答的所有信息,但这是一个令人困惑的主题,因此不要感到难过.这是一个摘要,可以帮助您更好地理解,并提出您想问的问题(而且,我对Laravel还是陌生的,所以我可能对这些不太满意)
Your question is a little confusing and doesn't have all the information for someone to answer, but it's a confusing topic, so don't feel bad. Here's a rundown that may help you better understand, and ask the question you wanted to ask (also, I'm newish to Laravel, so I may be off base with these)
-
make
方法用于实例化对象.当您说App::make('Data')
时,您是在告诉Laravel从类Data
实例化一个对象.
The
make
method is used to instantiate objects. When you sayApp::make('Data')
you're telling Laravel to instantiate an object from the classData
.
第1个警告,如果您调用make
并且已经将字符串Data
绑定到服务容器中的某个东西,Laravel将会返回该服务.这可能意味着Laravel实例化了一个新的服务对象,或者可能意味着Laravel返回了一个服务单例.
There's a caveat to number 1. If you call make
and have already bound the string Data
to something in the service container, Laravel will return the service instead. This may mean Laravel instantiates a new service object, or it may mean Laravel returns a service singleton
Laravel是否为服务返回单例或实例取决于服务的绑定方式
Whether or not Laravel returns a singleton or an instance for a service depends on how the service was bound
make
方法不绑定任何内容
您可以使用以下方法原型public function bind($abstract, $concrete = null, $shared = false)
You bind services with the application object's bind
method, defined on the container class with the following method prototype public function bind($abstract, $concrete = null, $shared = false)
看到第三个$shared
参数吗?如果是这样,您的服务将返回单例.如果为假,则您的服务将返回实例.
See that third $shared
parameter? If that's true your service will return a singleton. If it's false your service will return instances.
应用程序对象的singleton
方法是用于绑定服务的方法
回复:#7,这是singleton
#File: vendor/laravel/framework/src/Illuminate/Container/Container.php
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}
在上面的示例中,您将服务Data
绑定到了容器中.使用首字母大写的服务名称会引起问题-data
是一个更好的选择.如果由于某些原因未调用您的register
方法,则make
仍将使用全局类Data
In your examples above you're binding the service Data
into the container. Using a leading case service name is going to cause problems -- data
would be a better choice. If your register
method isn't called for some reason, make
will still instantiate an object with your global class Data
关于您的Facade-Facade是实例/单一性的额外一层.这是Facade类使用getFacadeAccessor
中的字符串从静态调用返回对象的方法
Regarding your Facade -- a Facade is an extra layer of instance/singleton-ness. Here's the method where the facade class uses the string from getFacadeAccessor
to return an object from a static call
#File: vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) return $name;
if (isset(static::$resolvedInstance[$name]))
{
return static::$resolvedInstance[$name];
}
return static::$resolvedInstance[$name] = static::$app[$name];
}
因此,外观使用$app[$name];
从容器中获取服务.这是ArrayAccess
,所以如果我们看一下offsetGet
So, a facade uses $app[$name];
to grab a service from the container. This is ArrayAccess
, so if we look at the definition of offsetGet
public function offsetGet($key)
{
return $this->make($key);
}
我们看到ArrayAccess
包装了对make
的调用.这意味着,如果您没有绑定服务,则外观访问将实例化一个对象.如果您将服务绑定为单例/共享服务,则外观访问将返回该单例.如果您将服务绑定为非单例/共享服务,则外观访问将实例化一个新对象.
We see ArrayAccess
wraps a call to make
. This means if you have no bound service, facade access will instantiate an object. If you have the service bound as a singleton/shared service, facade access will return that singleton. If you have the service bound as not a singleton/shared service, facade access will instantiate a new object.
如何,Facade本身会将其实例化的任何对象存储在static::$resolvedInstance
内部,以后对Facade的调用将返回该实例.这意味着Facade访问引入了第二个单例实现.绑定为单例的服务将存储在应用程序对象上,通过立面访问的服务将作为单例存储在Facade
类上.
HOWEVER, the Facade itself will store any object it instantiates inside static::$resolvedInstance
, and future calls to the facade will return this same instance. This means Facade access introduces a second singleton implementation. A service bound as a singleton will be stored on the application object, a service accessed via a facade will be stored as a singleton on the Facade
class.
这篇关于Laravel app-> bind和app-> singleton之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!