PHP OOP:可以在函数中看到变量而不将其作为参数传递吗?


PHP OOP: Can a variable be seen in a function without passing it as a param?

我想知道是否有人可以帮助我理解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,这将创建适当的控制器并将控制权移交给它的请求处理程序。

在一般情况下,一个好的设计可能比这更棘手,因为作为设计人员,在创建具有单一职责的类时,您的目标是减少更改它们的需要。如果一个类只有一个职责,那么只有当这个职责的需求改变时,这个类才需要被改变。