我对laravel在IOC容器和外墙方面提供的所有好东西感到有些困惑。由于我不是一位经验丰富的程序员,因此学习起来势不可挡。
我想知道,这两个例子之间的区别是什么:
“Foo”的立面。并通过App::bind()
“Foo”的立面。并通过App::singleton()
在我的最佳理解中,Foo::method()
将被重写为$app->make['foo']->method()
,因此在第一个示例中,将创建Foo
类的多个实例,而在第二个示例中,因为它是'通过App::singleton()
进行绑定,每次调用该对象上的Method时,都会返回Foo
的相同实例。
对不起,如果这个问题的答案显而易见,但我无法就此问题找到任何确认,而且无法明确解释。
答案 0 :(得分:57)
就是这样。
一个非常简单的证明是测试bevahior。由于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
方法。
如果绑定注册为shared(表示为singleton),则返回类实例,否则每次都返回一个新实例。
来源:https://github.com/laravel/framework/blob/4.2/src/Illuminate/Container/Container.php#L442
BTW,Container::singleton
与Container::bind
相同,第三个参数设置为true。
答案 1 :(得分:14)
外墙确实可以作为单身人士工作,即使底层绑定不是单身人士。
假设你有:
$app->bind('foo', 'FooConcrete'); // not a singleton
和
class Foo extends \Illuminate\Support\Facades\Facade {
protected static function getFacadeAccessor() { return 'foo'; }
}
然后这将像往常一样创建FooConcrete
的2个实例:
app('foo');
app('foo');
但是这只会创建FooConcrete
的一个实例并重复使用它:
Foo::someMethod();
Foo::someMethod();
这是因为resolveFacadeInstance()
存储已解析的实例。
但有一个例外。大多数情况下,定义的getFacadeAccessor()
会返回字符串,如上所示,但它也可以返回对象。 Schema
门面的示例:
protected static function getFacadeAccessor() {
return static::$app['db']->connection()->getSchemaBuilder();
}
在这种情况下,resolveFacadeInstance()
不会存储实例。
因此,如果getFacadeAccessor()
返回一个新实例,则每次调用Facade都会创建一个新实例。
答案 2 :(得分:3)
但在某处,我读到Laravel将通过外墙调用的课程视为单身人士?
因此,我遇到了这个问题:
我有一个通常通过
绑定的演示类$this->app->bind('demo', function() { return new Demo(); }
建立立面
protected static function getFacadeAccessor() { return 'demo'; }
该类本身看起来像这样
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; } }
你告诉我如果我在这个类上使用一个Facade,它将实例化该类的一个对象,然后在该对象上调用该方法。
我试了一下,发现这个非常奇怪(至少对我而言)的行为:
如果我
Demo::setVal1('13654');和
Demo::setVal2('random string')
我不应该使用Demo :: getVals()来检索我刚创建的值,是吗?由于每次使用facade方法时都会实例化一个新对象,一个对象如何检索另一个对象的属性?应该有三个不同的实例,但我仍然可以从其他实例中检索属性......