从闭包

时间:2016-05-27 08:58:35

标签: php scope closures

我很清楚全局变量是邪恶的,这是我稍后会讨论的问题。这不是我的代码库,但我已经分配了一些清理任务。

尝试改进代码库,我决定使用一个名为AltoRouter的软件包来实现简单的路由 - 我以前使用它并且它已经很好地用于我的目的。

现在,代码库使用了在全局范围内声明的大量变量。通常,然后使用global关键字提取这些变量。但由于某些原因,当我在闭包内工作时,这不起作用。

考虑这个简单的路由示例:

<?php
require 'vendor/autoload.php';
$router = new AltoRouter();

$router->map('GET', '/shops/[i:id]', function($id) {

    $_GET['shop_id'] = $id;
    require 'go_to_shop.php';
});

$match = $router->match();

if( $match && is_callable( $match['target'] ) ) {
    call_user_func_array( $match['target'], $match['params'] );
}

这会调用我的闭包设置变量并需要一个文件。

这会产生错误:

  

致命错误:在null中调用成员函数get()   第71行/vagrant/Core/CampaignHandler.php

现在,执行此操作的代码如下(第70-71行):

// Inside a method
global $serviceContainer;
$dispatcher = $serviceContainer->get("dispatcher");

通过提前包含文件来声明$serviceContainer

$serviceContainer = new ServiceContainer();
$serviceContainer->set("dispatcher", new EventDispatcher());

基本上,如果我将闭包的内容移到闭包之外,一切都运行得很好 - 但是一旦我从闭包内部做到这一点,通过全局作用域访问的所有变量都是空的 - 我没有关于原因的想法。

我尝试在关闭时使用use,这也不起作用。

我主要是寻求解释而不是解决方案。

3 个答案:

答案 0 :(得分:1)

全球有罪是有原因的。您会收到错误,因为在调用函数时未初始化全局。 globalrequire的混乱是确切的问题,您已经在尝试处理它。

在封闭本身中使用全局变量没有问题。这个例子完全正常:

global.php:

<?php
class Foo {
    public function bar() { return 'bar';}
}

$foo = new Foo;

test.php的:

<?php
require 'global.php';

$test = function($param) {
    global $foo;
    echo $param, $foo->bar();
}

call_user_func_array($test, ['baz']);

所以php test.php输出bazbar;

答案 1 :(得分:0)

我非常确定$serviceContainer变量在全局范围内不存在,但问题就是将该部分排除在外。

您是否无法使用use( $serviceContainer )语句将容器传递给匿名函数?这是一个更清晰的解决方案,然后不得不依赖全局。

function($id) use( $serviceContainer ) {

   $_GET['shop_id'] = $id;
   require 'go_to_shop.php';
}

偏离主题:不确定您之后使用该ID变量做什么以及为什么要将其重新放回到$ _GET变量中,但请注意。

答案 2 :(得分:-1)

请查看手册中的匿名函数 - 也称为闭包,实际上是对象。

http://php.net/manual/en/functions.anonymous.php

Theses callables具有扩展其范围的特定功能。

请参阅:示例#3从父作用域继承变量

$message = 'hello';

// No "use"
$example = function () {
  var_dump($message);
};
$example();

// Inherit $message
$example = function () use ($message) {
  var_dump($message);
};
$example();

确定要为$ _GET全局变量分配值?

$_GET['shop_id'] = $id;

您可以从altorouter参数中提取路线中的商店ID。 (见文件。)

$router->map( 'GET', '/', function() { .. }, 'home' );

// assuming current request url = '/'
$match = $router->match();

/*
array(3) { 
  ["target"]    => object(Closure)#2 (0) { } 
  ["params"]    => array(0) { } 
  ["name"]  => 'home' 
}
*/

或者,如果您想为会话存储ID,请使用$ _COOKIES或$ _SESSION全局变量。