【问题标题】:Using $_SERVER['SCRIPT_NAME'] to instantiate controller使用 $_SERVER['SCRIPT_NAME'] 实例化控制器
【发布时间】:2013-11-02 04:18:43
【问题描述】:

我在我的 php webapp 中使用 MVC 架构。我的架构非常简单,如果我以localhost/Dispatcher.php?class=SampleController&method=sampleMethod 这种方式向 url 发送请求,这将实例化控制器 SampleController 并调用此控制器的方法 sampleMethod。顺便说一句,我不能使用 .htaccess 文件。现在我想摆脱Dispatcher.php,所以我认为如果我将url的sintax更改为localhost/SampleController.php?method=sampleMethod之类的东西,我可以实现这一目标。为此,我必须使用$_SERVER['SCRIPT_NAME'] 来获取控制器类名。我所有的控制器都从Controller 扩展而来。我认为我可以在Controller.php 中实例化控制器。所以,我的Controller.php 看起来像这样。

<?php
//Enable errors
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);

//Include the controller
$include = explode("/",$_SERVER['SCRIPT_NAME'])[2]; //This return MainController.php
include_once $include;

//Get the method (Like this is an example I don't care the validations)
$method = $_GET['method'];

$class = explode(".",$include)[0]; //Get rid of the *.php extention
$controller = new $class(); 
$controller->$method(); // I get Class 'MainController' not found

include_once 'View.php';
class Controller {
    public $view;
    public function __construct() {
        $this->view = new View();
    }
}

?>

这是我的MainController.php

<?php
include_once 'Controller.php';
include_once 'MainModel.php';
class MainController extends Controller {

    public $model;

    public function __construct() {
        parent::__construct();
        $this->model = new MainModel();
    }

    public function index(){
        $this->view->render('mainView','headerMain','footerMain');

    }
}

?>

我在这里尝试点击这个网址MainController.php?method=index

所有名称都可以,路径也可以。顺便说一句,如果我硬编码我得到相同错误的路径,这可能是包含错误吗?如果我不能在Controller.php 中实现这一点,那么在某些地方我可以在不添加另一个 .php 文件的情况下处理控制器实例化? (我不想回去使用Dispatcher.php

更新 如果我以这种方式更改Controller.php,则可以,但我得到Fatal error: Cannot redeclare class maincontroller in MainController.php on line 9

<?php
include_once 'View.php';

//Enable errors
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);

//Include the controller
$include = explode("/",$_SERVER['SCRIPT_NAME'])[2]; //This return MainController.php

//Get the method (Like this is an example I don't care the validations)
$method = $_GET['method'];
$class = explode(".",$include)[0];

require($include);

$controller = new $class();
$controller->$method();


class Controller {
    public $view;
    public function __construct() {
        $this->view = new View();
    }
}
?>

解决方法

我通过这种方式实现了我想要的:

MainController.php

<?php
//Enable errors
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);

include_once 'Controller.php';
include_once 'MainModel.php';
class MainController extends Controller {

    public $model;

    public function __construct() {
        parent::__construct();
        $this->model = new MainModel();
    }

    public function index(){
        $this->view->render('mainView','headerMain','footerMain');

    }
}

require_once("Core.php");

?>

控制器.php

<?php
include_once 'View.php';

class Controller {
    public $view;
    public function __construct() {
        $this->view = new View();
    }
}
?>

Core.php

<?php
//Enable errors
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);

//Include the controller
$include = explode("/",$_SERVER['SCRIPT_NAME'])[2]; //This return MainController.php

//Get the method (Like this is an example I don't care the validations)
$method = $_GET['method'];
$class = explode(".",$include)[0];

$controller = new $class();
$controller->$method();

?>

但是这个解决方案仍然不能让我满意,这不是我想要的面向对象的解决方案。在Controller.php 中不是有什么办法吗?

【问题讨论】:

  • 这里的愚蠢问题:您包含的文件在同一路径中?
  • 哥们没有愚蠢的问题;)。是的,我强烈检查过。
  • 您可能想阅读this
  • @teresko 不错的信息。但我想要的很简单:我希望能够向SampleController.php 那里的类发送请求,从Controller 扩展,这个类包含一个名为doRouting 的方法,可以完成上述工作,我该怎么做在 SampleController.php? 的末尾,无需在类定义之外添加一些额外的行。如果我能做到这一点,我认为我有能力解决问题。

标签: php model-view-controller


【解决方案1】:

您的问题可能是在MainController.php 中,您在定义类之前调用​​了include_once 'Controller.php'。然后Controller.php 将不再包含MainController.php,因为include_once 注意到它已经被加载。如果再次使用包含MainController.phprequire,则MainController.php 中的include_once 将不再包含Controller.php,声明类并返回Controller.php。当Controller.php完成后,它会回到原来的MainController.php,这样就无法再次声明类了。

您也许可以在Controller.php 的末尾使用die()exit(),但我更喜欢声明一个函数,比如说Process(),它会在初始化后完成所有工作并将其作为最后一个调用MainController.php 的行。

Controller.php

<?php
//Enable errors
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);

function Process()
{
    //Get the method (Like this is an example I don't care the validations)
    $method = $_GET['method'];

    $class = explode(".",$include)[0]; //Get rid of the *.php extention
    $controller = new $class(); 
    $controller->$method(); // I get Class 'MainController' not found

    include_once 'View.php';
}

class Controller {
    public $view;
    public function __construct() {
        $this->view = new View();
    }
}

?>

MainController.php

<?php
include_once 'Controller.php';
include_once 'MainModel.php';
class MainController extends Controller {

    public $model;

    public function __construct() {
        parent::__construct();
        $this->model = new MainModel();
    }

    public function index(){
        $this->view->render('mainView','headerMain','footerMain');

    }
}

Process();

?>

【讨论】:

  • 所以我必须在每个控制器的末尾加上Process();。有没有办法摆脱它?或者只放在一个地方。
  • 就像我说的 - 你可以在 Controller.php 的末尾添加 exit() - 但这会是一个有点肮脏的解决方案。如果使用控制器的 URL 对您很重要,但没有那个小小的 Process() 调用,那么这对您来说可能没问题。
猜你喜欢
  • 2010-11-23
  • 2014-06-18
  • 2011-09-22
  • 1970-01-01
  • 2015-02-09
  • 1970-01-01
  • 2015-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多