【问题标题】:Access variables from the global scope within a closure从闭包内的全局范围访问变量
【发布时间】:2016-05-27 08:58:34
【问题描述】:

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

为了使代码库更智能,我决定使用一个名为 AltoRouter 的包来实现简单的路由 - 我以前使用过它,它对我的​​目的来说效果很好。

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

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

<?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'] );
}

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

这会产生错误:

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

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

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

$serviceContainer 是通过在早期包含一个文件来声明的:

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

基本上,如果我将闭包的内容移到闭包之外,一切都会完美运行 - 但是一旦我从闭包内部执行此操作,通过全局范围访问的所有变量都是空的 - 我没有想知道为什么。

我试过在闭包上使用use,这也不起作用。

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

【问题讨论】:

  • 声明$serviceContainer的文件是否包含在函数中...?
  • @deceze,不,它只是一个包含的文件,$serviceContainer驻留在全局变量范围内。

标签: php scope closures


【解决方案1】:

全局变量之所以邪恶是有原因的。您会收到错误,因为在调用函数时未初始化全局。 globals 和 requires 的混乱是确切的问题,您已经在尝试处理它。

在闭包中使用全局变量本身没有问题。这个例子工作得很好:

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

【讨论】:

  • 感谢您的解释。现在我有一些工作要做。
【解决方案2】:

我很确定 $serviceContainer 变量在全局范围内不存在,但问题将这部分排除在外。

您不能使用use( $serviceContainer ) 语句将容器传递给匿名函数吗?那将是一个更清洁的解决方案,然后不得不依赖全局变量。

function($id) use( $serviceContainer ) {

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

题外话:不知道你稍后对那个 id 变量做了什么,以及为什么你要把它放回 $_GET 变量中,但请小心。

【讨论】:

    【解决方案3】:

    请查看手册了解匿名函数——也称为闭包,实际上是对象。

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

    这些可调用对象具有扩展其范围的特定功能。

    参见:示例 #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 全局变量。

    【讨论】:

      猜你喜欢
      • 2011-08-23
      • 2020-12-17
      • 2013-12-25
      • 1970-01-01
      • 2016-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多