Laravel:区别 App::bind 和 App::singleton

Posted

技术标签:

【中文标题】Laravel:区别 App::bind 和 App::singleton【英文标题】:Laravel: Difference App::bind and App::singleton 【发布时间】:2014-10-03 10:37:14 【问题描述】:

我对 laravel 在 IOC 容器和外观方面提供的所有好处感到有些困惑。因为我不是一个经验丰富的程序员,所以学习起来会让人不知所措。

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

    “Foo”的外观并通过App::bind()注册在容器中

    “Foo”的外观并通过App::singleton()注册在容器中

在我的最佳理解中,Foo::method() 将被重写为 $app->make['foo']->method(),因此在第一个示例中,将创建 Foo 类的多个实例,而在第二个示例中,因为它是通过 App::singleton() 绑定的,所以相同每次调用该对象上的方法时,都会返回 Foo 的实例。

如果这个问题的答案很明显,我很抱歉,但我找不到任何关于这个问题的确认,也没有明确解释。

【问题讨论】:

不要因为不理解而道歉。相信我,你并不孤单! 【参考方案1】:

就是这样。

一个非常简单的证明是测试行为。由于 Laravel 应用程序只是扩展了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";

结果如预期:

Bind: test vs. test2

Singleton: test2 vs. test2

可能是一个肮脏的证明,但确实是一个。

所有的魔力都在于Container::make 方法。 如果绑定注册为共享(即单例),则返回类实例,否则每次都会返回一个新实例。

来源:https://github.com/laravel/framework/blob/4.2/src/Illuminate/Container/Container.php#L442

顺便说一句,Container::singletonContainer::bind 相同,但第三个参数设置为 true。

【讨论】:

非常感谢,这正是我想要的!关于何时使用单例以及何时最好实例化多个对象,我是否需要一个很好的资源? 如果您在整个请求中需要一个类的相同实例,您应该考虑使用单例方法(例如购物车),因为其他一切都可以绑定。 如果我错了,请纠正我,但是如果在通过 App::bind() 绑定的底层类上使用了外观,那么 Laravel 会实例化底层类的新对象吗?如果是这样,该对象本身是否可访问,因为每次使用外观上的方法时都会实例化它? 抱歉我的回复晚了。正如文档指出的那样,外观仅“为应用程序的 IoC 容器中可用的类提供“静态”接口”(source)。 你能举一个真实的例子来说明绑定和单例的区别吗?【参考方案2】:

但是我在某处读到 Laravel 总是将通过外观调用的类视为单例?

因此,我遇到了这个问题:

我有一个通常通过

绑定的演示类
$this->app->bind('demo', function()  return new Demo(); 

设置门面

受保护的静态函数 getFacadeAccessor()  return 'demo'; 

类本身是这样的

类演示
    

        私人 $value1;
        私人 $value2;

        公共函数 setVal1($value)
        
            $this->value1 = $value;
        

        公共函数 setVal2($value)
        
            $this->value2 = $value;
        

        公共函数 getVals()
        
            返回 '​​Val 1: ' 。 $this->value1 。 ' 值 2:' 。 $this->value2;
        

    

你告诉我,如果我要在这个类上使用外观,它会实例化该类的一个对象,然后调用该对象上的方法。

但我又测试了一些,发现这种(至少对我而言)非常奇怪的行为:

如果我这样做了

Demo::setVal1('13654');
Demo::setVal2('随机字符串')

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

【讨论】:

Gras Double 在他的解决方案中很好地回答了这个问题......“即使底层绑定不是单例,外墙也可以作为单例工作。”因此,当您使用外观时,使用 bind() 或 singleton() 都没有关系,无论哪种方式,行为都是相同的。差异仅在您创建新对象时才重要,例如使用 App::make()。【参考方案3】:

即使底层绑定不是单例,门面也可以作为单例工作。

假设你有:

$app->bind('foo', 'FooConcrete'); // not a singleton

和:

class Foo extends \Illuminate\Support\Facades\Facade 
    protected static function getFacadeAccessor()  return 'foo'; 

然后这将像往常一样创建 2 个FooConcrete 实例:

app('foo');
app('foo');

但这只会创建FooConcrete 的一个实例并重用它:

Foo::someMethod();
Foo::someMethod();

这是因为resolveFacadeInstance()存储了解析的实例。

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

protected static function getFacadeAccessor() 
    return static::$app['db']->connection()->getSchemaBuilder();

在这种情况下,resolveFacadeInstance() 不会存储实例。

因此,如果getFacadeAccessor() 返回一个新实例,则对 Facade 的每次调用也会创建一个新实例。

【讨论】:

这就是为什么如果需要你可以使用 clearResolvedInstances() 方法来删​​除存储的实例,所以如果你想在 Facade 上的每次调用中获取一个新对象,你可以在 @返回具体字符串之前的 987654335@ 方法。 您应该使用clearResolvedInstance()(没有“s”)只清除您需要的内容,而不是所有内容。不过,最好只返回一个实例。

以上是关于Laravel:区别 App::bind 和 App::singleton的主要内容,如果未能解决你的问题,请参考以下文章

wifi 路由模式和AP模式有啥区别?

如何替换 Laravel Builder 类

WDS AP ROUTER三种模式有啥区别???????

无线路由器ap模式和router模式有啥区别

无线AP的Fat模式和Fit模式有什么区别?

sh 该程序自动为基于Laravel框架的应用程序的公开发布创建一个干净的存档。为了安全起见,您需要ap