PHP - 体系结构,变量范围问题

时间:2013-03-03 10:33:58

标签: php global-variables scope

我现在正在编写一个应用程序,应该尽可能简单。我的控制器实现渲染($ Layout)方法,该方法只执行以下操作:

public function render($Layout) {
  $this->Layout = $Layout;
  include( ... .php)
}

我真的不明白以下问题:在我的控制器中,我定义了一个变量:

public function somethingAction() {
  $someVariable = "something";
  $this->render('someLayout');
}

在php视图文件中(我已经包含在渲染函数中)我尝试回显变量,但没有任何内容。但是,如果我声明我的动作方法如下:

public function somethingAction() {
  global $someVariable;
  $someVariable = "something";
  $this->render('someLayout');
}

在我看来是这样的:

global $someVariable;
echo $someVariable;

确实有效。每次写单词全球仍然很烦人。

我该怎么做?我宁愿不使用$ _GLOBAL数组。例如,在Cake PHP中,有一种方法,如 $ this-> set('varName',$ value)。然后我可以在视图中以 $ varName 的形式访问该变量。怎么做?

2 个答案:

答案 0 :(得分:3)

来自PHP Manual on include:

  

当包含文件时,它包含的代码将继承发生包含的行的变量范围。从那时起,调用文件中该行可用的任何变量都将在被调用文件中可用。但是,包含文件中定义的所有函数和类都具有全局范围。

当你这样做时

public function somethingAction() {
  $someVariable = "something";
  $this->render('someLayout');
}

$someVariable变量仅限于somethingAction()范围。调用render()方法不会神奇地使变量在render()中可用,因为render()方法具有自己的变量范围。可能的解决方案是

public function somethingAction() {
  $this->render(
      'someLayout', 
      array(
          'someVariable' => 'something'
      )
    );
}

然后将render()更改为

public function render($Layout, array $viewData) {
    $this->Layout = $Layout;
    include( ... .php)
}

您可以访问所包含文件中的$viewData,前提是您没有尝试在其他功能或方法中使用它,例如:如果您包含的文件如下所示:

<h1><?php echo $viewData['someVariable']; ?></h1>

它会起作用,但如果它看起来像这样:

function foo() {  
    return $viewData['someVariable']; 
}
echo foo();

它无效,因为foo()拥有自己的变量范围。

然而a controller's sole responsibility is to handle input。渲染是View的责任。因此,您的控制器根本不应该有render()方法。考虑将方法移动到View类,然后执行

public function somethingAction() {
  $view = new View('someLayout');
  $view->setData('someVariable', 'something');
  $view->render();
}

然后可以像这样实现View对象的render()方法:

class View
…
    $private $viewData = array();       

    public function setData($key, $value) 
    {
        $this->viewData[$key] = $data;
    }

    public function render()
    {
        extract($this->viewData, EXTR_SKIP);
        include sprintf('/path/to/layouts/%s.php', $this->layout);
    }

extract函数将使用其键作为名称导入当前作用域中数组的值。这样,您就可以将viewData中的数据用作$someVariable而不是$this->viewData['someVariable']。在使用之前,请确保您了解extract的安全隐患。

请注意,这只是您当前做事方式的一种可能替代方案。您也可以从控制器中完全移出视图。

答案 1 :(得分:0)

使用global您隐式使用$_GLOBALS数组。

不推荐示例,因为全局变量永远不是一件好事:

function something() {
  global $var;
  $var = 'data';
}

// now these lines are the same result:
echo $_GLOBALS['var'];
global $var; echo $var;

为什么不简单地使用$ this-&gt;设置功能?

public function render($Layout) {
  $this->Layout = $Layout;
  include( ... .php)
}

public function somethingAction() {
  $this->set('someVariable', "something");
  $this->render('someLayout');
}

// in a framework's managed view:
echo $someVariable;

我很抱歉不详细了解您的框架,但这非常有意义。

实际上它是如何完成的:有一个本地extract函数,它将一个关联数组加载到当前符号表中:

array( 'var0' => 'val0', 'var1' => 'val1')

变为

echo $var0; // val0
echo $var1; // val1

这很可能是'会发生什么'。