PHP -体系结构,变量作用域问题


PHP - architecture, issue with variables scope

我现在正在写一个应用程序,这应该是尽可能简单。我的控制器实现render($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这个词还是很烦人。

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

From 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()有它自己的变量作用域。

然而,控制器的唯一职责是处理输入。呈现是视图的职责。因此,控制器根本不应该有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之前,请确保您了解它的安全含义。

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

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

不推荐使用示例,因为全局变量从来不是一个好东西:

function something() {
  global $var;
  $var = 'data';
}
// now these lines are the same result:
echo $_GLOBALS['var'];
global $var; echo $var;

为什么不直接使用$this->set函数呢?

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

很可能就是这样。