我想知道是否有人可以帮助我理解OO PHP的这个特殊方面,因为它已经抓住了我几次了。
我在文件的顶部指定了一个变量,如下所示
$route = explode('/', $_SERVER["REQUEST_URI"]);
// Shorthand
$r1=$route[0]; $r2=$route[1]; $r3=$route[2];
然后我尝试在上面代码下面写的函数中使用$r1等。
function edit($id)
{
$_SESSION['path'] = $r1 . "/" . $r2 . "/" . $r3;
require 'app/controller/edit.php';
new Controller($id);
}
由于某些原因,$ r1,$r2, $r3不能在函数中看到。
Notice: Undefined variable: r1 in C:'wamp'www'options.ex'public_html'app'options.php on line 77
如果我将$r变量传递给函数,我想不会有问题,但由于它们是全局声明的,我想知道为什么它们不可见而不这样做,因为它们的作用域大概是全局的?
谢谢。
编辑-完整代码。
<?php
require_once 'load.php';
// Clean and prepare query string
$route = explode('/', $_SERVER["REQUEST_URI"]);
// Trim outer exmpty parameters caused by leading/trailing slash
if($route[count($route)-1]=='') unset($route[count($route)-1]);
if($route[0]=='') unset($route[0]);
$route = array_values($route);
// If any parameters are undefined, set them to ''
if(!isset($route[0])) { $route[0]=''; $route[1]=''; $route[2]=''; }
elseif(!isset($route[1])) { $route[1]=''; $route[2]=''; }
elseif(!isset($route[2])) { $route[2]=''; }
// Shorthand
$r1=$route[0]; $r2=$route[1]; $r3=$route[2];
// Choose route, else default to dash
if($r1=='dashboard' && $r2=='' && $r3=='') dashboard();
elseif($r1=='staff' && $r2=='add' && $r3=='') add_staff();
elseif($r1=='staff' && $r2=='edit' && $r3!='') edit_staff($r3);
else header("location: http://local.options.ex/dashboard");
// Dashboard: Main entry point after login.
function dashboard()
{
require 'app/controller/dashboard/dashboard.php';
new Controller();
}
// Staff related interfaces ----------------------------------------------------
function add_staff()
{
require 'app/controller/staff/add_staff.php';
new Controller();
}
// ----------------------------------------
function edit_staff($staff_id)
{
$_SESSION['path'] = $r1 . "/" . $r2 . "/" . $r3;
require 'app/controller/staff/edit_staff.php';
new Controller($staff_id);
}
// ----------------------------------------
只是为了澄清,$r*变量在这里之后不会再次使用,因此方便地使用在会话中存储
这不是面向对象-在面向对象中,你会声明一个类,使r1, r2和r3成为它的属性,然后它们将在类的每个方法中可用。这里有一个关于类的小教程。
使用全局变量是一个坏主意。
编辑下面是一个示例代码,就像Sohnee问的那样:
Class Route {
var $r1;
var $r2;
var $r3;
function __construct($url)
{
$route = explode('/', $url);
// Shorthand
$this->r1=$route[0]; $this->r2=$route[1]; $this->r3=$route[2];
}
function test()
{
$path = $this->r1 . "/" . $this->r2 . "/" . $this->r3;
echo $path;
}
}
$a = new Route('http://stackoverflow.com/questions/');
$a->test();
为了在函数中使用全局变量,您必须通过以下方式
$route = explode('/', $_SERVER["REQUEST_URI"]);
// Shorthand
$r1=$route[0]; $r2=$route[1]; $r3=$route[2];
// ...
function edit($id)
{
global $r1, $r2, $r3; // after this the variables are available in function scope
}
另一个选项是使用全局数组$GLOBALS。使用这个数组可以从任何作用域访问全局变量,如下所示:
if ($GLOBALS["r1"] == "some value")
{
// do something
}
将此添加到函数中。
$r1, $r2, $r3;
告诉函数使用全局作用域中的变量
全局变量可以在使用$GLOBALS
$GLOBALS — References all variables available in global scope
http://php.net/manual/en/reserved.variables.globals.php <?php
$baz = 'foo';
clas Bar {
public function __construct() {
echo $GLOBALS['baz'];
}
}
或在函数内部声明变量全局
function bar() {
global $baz;
echo $baz
}
如果$r1, $r2和$r3是在任何类或函数定义之外定义的,您可以使用global关键字访问它们,或者直接从$GLOBALS数组调用它们。e.x。
function edit($id){
global $r1, $r2, $r3; //Rest of the function below this
或
$_SESSION['path'] = $GLOBALS['r1'].'/' //... etc.
全局变量可以在函数中访问,如果您将它们声明为全局(这会创建对全局的局部引用)。然而,全局变量是不好的。
如果变量定义发生在"app/controller/edit.php"中,那么问题就像警告告诉你的那样:变量还没有定义。您在一行中使用它们,但是在下一行之前不包含定义它们的文件,因此它们还没有定义。这就好像函数是:
function edit($id) {
$_SESSION['path'] = $r1 . "/" . $r2 . "/" . $r3;
$route = explode('/', $_SERVER["REQUEST_URI"]);
// Shorthand
$r1=$route[0]; $r2=$route[1]; $r3=$route[2];
...
}
我不建议使用明显的修复方法:将require移到使用变量的行之前,因为这与全局变量有一个共同的大问题:变量似乎神奇地出现了,没有指示如何或在哪里出现,使得仅仅通过阅读函数就很难理解函数(以及其他代码)。这是耦合的一种形式。
通过包含文件来执行代码有时是一个有用的技巧,但它也经常导致问题(如这个问题所示)。通常,include文件应该只定义一些东西。对于OO方法,采用包含的文件正在执行的任何任务,并找出代码试图实现的总体任务。然后,将每个任务分配给(单独)负责完成每个总体任务的类。在这种情况下,特定的任务是将请求分解为路由,而整个作业是将请求分派给控制器。然后应该有一个dispatcher类,它将请求发送到适当的控制器,并使用解析路由的方法。该方法(可能是私有的或受保护的,并从构造函数调用)可以将路由存储在实例变量中,以节省时间。
class RouteDispatcher {
protected $route;
function __construct() {
$this->_parseRoute();
...
}
function dispatch() {
...
}
protected function _parseRoute() {
$this->route = explode('/', $_SERVER['REQUEST_URI']);
}
...
}
入口点(首先调用来处理每个请求的脚本)将实例化RequestDispatcher
,设置任何适当的属性或调用任何必要的方法,然后调用RequestDispatcher::dispatch
,这将创建适当的控制器并将控制权移交给它的请求处理程序。
在一般情况下,一个好的设计可能比这更棘手,因为作为设计人员,在创建具有单一职责的类时,您的目标是减少更改它们的需要。如果一个类只有一个职责,那么只有当这个职责的需求改变时,这个类才需要被改变。