为什么使用闭包来分配而不是直接为键赋值?

时间:2017-04-26 07:12:25

标签: php closures variable-assignment

我正在观看this video,并且在7:10他正在添加数据库依赖项,并使用闭包来分配值。

我的问题是为什么不直接使用直接分配,我的意思是不这样做:

$container['db'] = $capsule;

相当于这样做:

$container['db'] = function ($container) use ($capsule) {
    return $capsule;
}

如果没有,有什么区别,哪种方式更好?

3 个答案:

答案 0 :(得分:2)

TLDR 它因为将依赖关系定义为闭包使得依赖注入容器可以按需构建它们,因此您不必担心它们的定义顺序和手动管理他们的依赖。

Pimple是依赖注入容器,它应该通过简单方便的方式管理其依赖项来帮助您设置对象。

如果直接为某个键指定值,则Pimple将该值称为参数,当您需要访问该键时,它只返回该确切值:

$container['sample-param'] = 'foo';
echo $container['sample-param'];
//output: foo

但重点是,这个sample-param不需要任何设置,它只是一个值,我们对此很好。但假设以下服务设置:

$container['myService'] = function($c) {
    $service = new \Some\Complicated\Service();
    //this service depends on cache service
    $service->setCache($c['cache']);
    return $service;
}

$container['cache'] = function($c) {
    $cache = new \Cache\Driver();
    //our cache driver needs a db connection
    $cache->setDbConnection($c['db']);
    return $cache;
}

$container['db'] = function($c) {
    //our database connection requires some parameters
    $dbConnection = new \Database\Connection($c['db-config']);
    return $dbConnection;
}

$container['db-config'] = [
    'username' => 'foo',
    'password' => 'bar',
    'host' => 'localhost'
];

//Now we want to user our service:
$container['myService']->doSomething();

请注意我用来定义容器中不同键的顺序。

myService需要cache,但缓存定义位于myService定义之后。这就是Pimple正在帮助的地方,这就是我们将容器传递给每个闭包的原因,因为Pimple将根据需要构建我们的依赖。当我们需要访问myService时,Pimple查看其内部数据存储,如果它先前已成功构建并存储myService,它将返回相同的实例,否则它将调用我们的闭包来构建它。当调用我们的闭包时,它会询问Pimple($ c是Pimple容器)给它 dependecies (在这种情况下是cache服务)。 Pimple在缓存上应用相同的东西,如果它还没有构建,它将构建它等等......直到它到达需要简单的params的部分,如db-config将立即返回。在这个闭包调用链中,构建了我们的对象及其所有依赖项。

现在想象如果我们使用简单的值而不是闭包会发生什么?在这种情况下,当我们想构建myService 时,我们必须处理它的依赖关系。我们必须确保其依赖关系定义之前我们定义服务本身,而我们必须处理与管理依赖关系相关的其他问题。在这种情况下,我们无法定义我们的myService假设有一个cache服务可用,稍后会定义。

答案 1 :(得分:0)

在该视频中,他使用Slim框架作为容器,默认情况下使用Pimple作为容器。

http://pimple.sensiolabs.org/

在该页面的文档中,它提到了以下内容

  

定义服务服务是一个作为一部分做某事的对象   一个更大的系统。服务示例:数据库连接,a   模板引擎或邮件程序。几乎任何全局对象都可以是   服务。

     

服务由返回实例的匿名函数定义   一个对象:

// define some services
$container['session_storage'] = function ($container) {
    return new SessionStorage('SESSION_ID');
};

$container['session'] = function ($container) {
    return new Session($container['session_storage']);
};
     

请注意,匿名函数可以访问当前容器实例,允许引用其他服务或参数。

按设计,容器期望调用函数

Pimple的容器实现\ArrayAccess接口(seen here),这意味着它们可以使对象像一个数组,而不一定是一个。在源代码中,您会注意到offsetSetoffsetGet,这是您执行此操作时发生的情况:

$container['a'] = function($c){ return new Blah();}

$thing = $container['a']; 

tl; dr 这是一个特定于Pimple容器的东西,而不是特定于PHP的东西。

答案 2 :(得分:-1)

它完全不同。第一个$container['db'] = $capsule;
表示$container数组具有db键且该键等于$capsule, 第二个意味着你有一个$container数组,db键有值闭包。转储两个结果时可以看到区别:

关闭示例:

$capsule = 1;
$container['db'] = function ($container) use ($capsule) {
    return $capsule;
};
var_dump($container); 

结果:

Array(1) {
  ["db"]=>
  object(Closure)#1 (2) {
    ["static"]=>
    array(1) {
      ["capsule"]=>
      int(1)
    }
    ["parameter"]=>
    array(1) {
      ["$container"]=>
      string(10) "<required>"
    }
  }
}

非封闭示例:

$capsule = 1;
$container['db'] = $capsule;    
var_dump($container);

结果:

result array(1) {
  ["db"]=>
  int(1)
}

您可以在php手册中阅读有关闭包的内容,以便更好地了解其角色。 PHP Closures Manual