索引中定义的变量不可访问

Variable defined in index not accessible

我有一个 php 框架,我在其中通过索引文件路由所有请求。在索引文件中我有:

index.php

$module = new module();
$module->SetName("user");
$call = new call();
$call->SetController("login");

然后我进行一些处理以找到请求的控制器文件。一旦找到,我就会

$call->LoadController()

此方法需要模块指定的文件并调用。在这种情况下它会做 require_once CONTROLLERS . "user/"."login.php"

到目前为止一切都很好。在我加载的控制器文件中

controllers/user/login.php
$call->SetView("login")

我得到一个 php 错误 undefined variable $call

我不知道为什么?

原因是,通过 including/requiring 一个文件,您的变量范围与您预期的正好相反。有关详细信息,请查看 PHP Documentation

这里有一个例子,非常清楚:

vars.php

<?php

$color = 'green';
$fruit = 'apple';

?>

test.php

<?php

echo "A $color $fruit"; // A

include 'vars.php';

echo "A $color $fruit"; // A green apple

?>

$call 在 LoadController() 内部是未知的,因为它在全局范围内。包含的控制器文件共享 LoadController 的范围。这就是为什么不能在控制器文件中使用 $call 的原因。 有以下三种解决方案: 您可以在 LoadController() 中使用 "global" 关键字,因此 $call 在 LoadController() 和包含的控制器文件中是已知的:

class module
{
   public function LoadController()
   {
      global $call;
      require_once('controllers/user/login.php');
   }
}

但是这个解决方案很丑。

第二种解决方案是在包含的控制器文件中使用 $this->SetView() 而不是 $call->SetView() 。此解决方案的缺点是您在包含的文件中有多个 $this,并且您不知道 class 对 $this 意味着什么。仍然比第一个解决方案更好。

第三种解决方案是使用单例模式。你只需要class模块的一个对象,它会为你避免很多麻烦。然后您可以从任何您想要的地方调用 SetView(),而不会出现全局变量和未知范围的问题。您可以这样调用 SetView():module::getInstance()->SetView()。查看单例模式:https://duckduckgo.com/?q=singleton+pattern