Laravel app->bind 和 app->singleton 之间的区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25797594/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 10:05:50  来源:igfitidea点击:

Laravel Difference `between app->bind` and `app->singleton`?

laravellaravel-4singletonfacade

提问by Rob

I've been trying to figure out what the difference between app->bindand app->singletonare when setting up a service provider in Laravel. I was under the impression that if I register an singletonit would return the same instance of the object each time it was called vs bindwhich would be a new instance.

我一直试图弄清楚在 Laravel 中设置服务提供程序时app->bind和之间的区别app->singleton。我的印象是,如果我注册一个,singleton它会在每次调用它时返回对象的相同实例,而bind这将是一个新实例。

Here is simple example:

这是一个简单的例子:

Facade:

正面:

use Illuminate\Support\Facades\Facade;

class DataFacade extends Facade
{
    protected static function getFacadeAccessor() { 
        return 'Data';
    }
}

ServiceProvider:

服务提供者:

use Illuminate\Support\ServiceProvider;

class DataServiceProvider extends ServiceProvider
{
    public function register() {
        $this->app->singleton('Data', function() {
            return new Data;
        });
    }
}

Class:

班级:

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');

And run that we will see the appropriate behavior between bindand singletonwith foobeing printed out once and then twice respectively. However if we run it through the facade like so:

然后运行,我们将看到bind和之间的适当行为singletonfoo分别打印一次和两次。但是,如果我们像这样通过门面运行它:

Data::set('test', 'test');
Data::set('cheese', 'cheese');

When it's a singleton I would expect both testand cheeseto be available and when it's a bindI'm not sure what I would expect to be available via the facade, but it seems like there is no difference.

当它是单身时,我希望testcheese都可用,而当它是一个时,bind我不确定我希望通过外观获得什么,但似乎没有区别。

It's the facade treating everything as a singleton?

这是外观将一切视为singleton?

回答by Alan Storm

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)

您的问题有点令人困惑,并且没有可供某人回答的所有信息,但这是一个令人困惑的话题,所以不要难过。这是一个纲要,可以帮助您更好地理解,并提出您想问的问题(另外,我是 Laravel 的新手,所以我可能对这些不了解)

  1. The makemethod is used to instantiate objects. When you say App::make('Data')you're telling Laravel to instantiate an object from the class Data.

  2. There's a caveat to number 1. If you call makeand have already bound the string Datato 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

  3. Whether or not Laravel returns a singleton or an instance for a service depends on how the service was bound

  4. The makemethod doesn't bind anything

  5. You bind services with the application object's bindmethod, defined on the container class with the following method prototype public function bind($abstract, $concrete = null, $shared = false)

  6. See that third $sharedparameter? If that's true your service will return a singleton. If it's false your service will return instances.

  7. The application object's singletonmethod is a method for binding services

  1. make方法用于实例化对象。当你说App::make('Data')你告诉 Laravel 从 class 实例化一个对象时Data

  2. 第 1 条有一个警告。如果您调用make并且已经将字符串绑定Data到服务容器中的某些内容,Laravel 将改为返回服务。这可能意味着 Laravel 实例化了一个新的服务对象,也可能意味着 Laravel 返回了一个服务单例

  3. Laravel 是否为服务返回单例或实例取决于服务是如何绑定的

  4. make方法不绑定任何东西

  5. 您使用应用程序对象的bind方法绑定服务,在容器类上使用以下方法原型定义public function bind($abstract, $concrete = null, $shared = false)

  6. 看到第三个$shared参数了吗?如果这是真的,您的服务将返回一个单身人士。如果它是假的,您的服务将返回实例。

  7. 应用程序对象的singleton方法是绑定服务的方法

Re: #7, here's the definition of singleton

回复:#7,这是定义 singleton

#File: vendor/laravel/framework/src/Illuminate/Container/Container.php
public function singleton($abstract, $concrete = null)
{
    $this->bind($abstract, $concrete, true);
}

In your examples above you're binding the service Datainto the container. Using a leading case service name is going to cause problems -- datawould be a better choice. If your registermethod isn't called for some reason, makewill still instantiate an object with your global class Data

在上面的示例中,您将服务绑定Data到容器中。使用领先的案例服务名称会导致问题——data这将是一个更好的选择。如果您的register方法由于某种原因未被调用,make仍将使用您的全局类实例化一个对象Data

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 getFacadeAccessorto return an object from a static call

关于你的门面——门面是一个额外的实例/单一层。这是外观类使用字符串 fromgetFacadeAccessor从静态调用返回对象的方法

#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];
}

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

因此,外观用于$app[$name];从容器中获取服务。这是ArrayAccess,所以如果我们看一下offsetGet

public function offsetGet($key)
{
    return $this->make($key);
}

We see ArrayAccesswraps 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.

我们看到ArrayAccess包装了对 的调用make。这意味着如果您没有绑定服务,门面访问将实例化一个对象。如果您将服务绑定为单例/共享服务,门面访问将返回该单例。如果您将服务绑定为不是单例/共享服务,门面访问将实例化一个新对象。

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 Facadeclass.

然而, Facade 本身将存储它在其中实例化的任何对象static::$resolvedInstance,并且对 Facade 的未来调用将返回相同的实例。这意味着 Facade 访问引入了第二个单例实现。绑定为单例的服务将存储在应用程序对象中,通过外观访问的服务将作为单例存储在Facade类中。