拉拉维尔 "应用>绑定"和"应用>单例"之间的区别?



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

这里有一个简单的例子:

立面:

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

服务提供商:

use IlluminateSupportServiceProvider;
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;
    }
}

如果我们做这样的事情:

$instance = App::make('Data');
$instance->set('foo', 'foo');
$instance2 = App::make('Data');
echo $instance->get('foo');
echo $instance2->get('foo');

运行该程序,我们将看到bindsingleton之间的适当行为,其中foo分别打印一次和两次。然而,如果我们像这样运行它:

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

当它是单例时,我希望testcheese都可用,而当它是bind时,我不确定我希望通过facade提供什么,但似乎没有什么区别。

这是把所有东西都当作singleton的门面吗?

你的问题有点令人困惑,没有所有的信息可以让别人回答,但这是一个令人困惑的话题,所以不要感到难过。以下是一个概述,可以帮助你更好地理解,并提出你想问的问题(此外,我对Laravel还不熟悉,所以我可能对这些不熟悉)

  1. make方法用于实例化对象。当你说App::make('Data')时,你是在告诉Laravel实例化类Data中的一个对象。

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

  3. Laravel是否返回服务的单例或实例取决于服务的绑定方式

  4. make方法不绑定任何

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

  6. 看到第三个$shared参数了吗?如果这是真的,您的服务将返回一个singleton。如果是false,您的服务将返回实例。

  7. 应用程序对象的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实例化对象

关于你的Facade——Facade是一个额外的实例/单例层。以下是facade类使用getFacadeAccessor中的字符串从静态调用返回对象的方法

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

因此,facade使用$app[$name];从容器中获取服务。这是ArrayAccess,所以如果我们看看offsetGet 的定义

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

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

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

最新更新