Laravel差异`在app-> bind`和`app-> singleton`之间?

时间:2014-09-11 21:56:19

标签: laravel laravel-4 singleton facade

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

这是一个简单的例子:

门面:

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 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时,我不确定我期望通过立面提供什么,但似乎没有区别。

这是将所有事物视为singleton的立面?

1 个答案:

答案 0 :(得分:26)

你的问题有点令人困惑,并没有让别人回答的所有信息,但这是一个令人困惑的话题,所以不要感到难过。这是一个可能有助于你更好地理解的纲要,并提出你想问的问题(另外,我对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. 定义
  7. 查看第三个$shared参数?如果这是真的,您的服务将返回单身人士。如果它是假的,您的服务将返回实例。

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

  9. 回复:#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访问将实例化一个新对象。

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