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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 17:44:16  来源:igfitidea点击:

Laravel: Difference App::bind and App::singleton

phpooplaravel-4ioc-containerfacade

提问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:

我想知道,这两个例子有什么区别:

  1. A facade to 'Foo' and registered in the container via App::bind()

  2. A facade to 'Foo' and registered in the container via App::singleton()

  1. 'Foo' 的外观并通过以下方式在容器中注册 App::bind()

  2. '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 Fooclass will be created and in the second example, since it's bound via an App::singleton(), the same instance of Foowill 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::makemethod. 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::singletonis the same as Container::bindwith 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 FooConcreteand 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 SchemaFacade:


不过也有例外。大多数情况下,定义getFacadeAccessor()返回一个字符串,如上所示,但它也可以返回一个对象SchemaFacade 中的示例:

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() 来检索我刚刚创建的值,对吗?由于每次使用外观方法时都会实例化一个新对象,一个对象如何检索另一个对象的属性?应该有三个不同的实例,但我仍然能够从其他实例中检索属性......