我正在使用 CodeIgniter 框架开发另一个项目,该框架有一个主 Controller 文件,用于构建网站上的所有页面。
输入“domain.com/about”等网址将在 Controller 文件中运行“function about(){”,该文件会加载到该页面的各个组件中。
大部分的魔力都是由 CodeIgniter 或其他项目成员处理的,所以我不确定这是如何发生的。
我希望在不使用任何框架的情况下实现同样的目标,但完全不知道如何实现它。我知道我可以在“domain.com?load=about”的某个地方有一个 url,并使用它来运行该函数,但我希望该 URL 干净,并且易于访问者访问输入。
所以,我的问题是..我如何设置我的网站,使其始终指向单个文件“controller.php”,然后运行一个与 URL 中输入的内容相匹配的函数,并且具有该函数URL 没有引导我离开 Controller 页面? (也就是说,如果我输入“domain.com/about”,我不想进入 about.php 页面!)
如果这个问题很难理解,或者如果我对任何事情采取了错误的方法,我提前道歉。另外,由于缺乏示例和描述......我真的不知道如何更具体。如果您需要查看或了解任何内容,请提出,我会尽力澄清!
谢谢!
最佳答案
您对此没有太多好的答案。让我们添加更多细节。
CodeIgniter 的工作原理
URL 路由
CodeIgniter 的第一步实际上是在 CodeIgniter 本身之外完成的。您将在 HTTP 守护程序中找到此步骤。如果是Apache,你会看到类似这样的重写规则:
RewriteRule ^(.+)$ /index.php?$1 [L]
如果你正在运行 nginx,你会看到:
rewrite ^/(.+)$ /index.php?/$1 last;
这是每个框架的核心指令之一,并将导致它处理和解析每个请求(基于 RewriteCond
/try_files
指令,可能会包括找到或未找到的文件)。用户提供的查询字符串将在 $_SERVER['QUERY_STRING']
中提供。请记住这一点,我们将不止一次地讨论这一点。
进入框架
如果您计划构建一个框架,您的框架应该具有称为路由器的功能。这是一个简洁的小类(或类集合),它将处理路线的动态创建。路由是 URI(可能包含通配符)和 Controller 的函数(或多个函数)之间的定向映射。
这一点经常被第一次编写自己的框架的人所忽视,并且可以区分可以工作的东西和使用起来非常痛苦的东西(PHP 中的差异很小。这确实变得很明显其他技术)。
所以。路由器。获取路由列表,将它们转换为类和函数。我们需要缓存 Controller 并提供它们的动态分配,因此我们将引入一个新概念:控制反转。如果您使用过较新的框架(Kohona、Laravel 等),您会对此感到熟悉。实际上,它允许您将类名绑定(bind)到转到字符串,并通过中介器控制此类类的实例化(从而遵循好莱坞原则 - 您请求 Controller ,而不是实例化它)。
经典的 IoC 包装器如下所示:
class IoC {
private static $cache = array();
private static $singletons = array();
public static function register($name,$className,$isSingleton=false) {
if (!isset(self::$cache[$name])) {
self::$cache[$name] = array("class" => $className, "singleton" => !!$isSingleton);
}
}
public static function instance($name) {
if (!isset(self::$cache[$name])) throw new Exception("Class not found in IoC container");
$cN = self::$cache[$name]['class'];
if (!empty(self::$cache[$name]['singleton'])) {
if (!isset(self::$singletons[$cN])) {
self::$singletons[$cN] = new $cN();
}
return self::$singletons[$cN];
}
else {
return new $cN();
}
}
}
这有很多好处:
- 您很可能有一天决定将 Controller 从
Controller1
更改为Controller2
。通过使用IoC
包装器来解决这个问题,您可以省去一些麻烦 - 不必遍历整个代码 - 本地处理
单例
,而不会使它们难以进行单元测试
所以。凭借我们的知识,我们现在可以使用 IoC::instance("ourkeyword"); 基于我们选择的任意关键字实例化一个类。我们稍后会大量使用它。首先,有一个警告:此 IoC 包装器假定您将使用 spl_autoload 来延迟加载您的类。
路由器本身将类似于:
class Router {
public $routes = array();
public function register($route, $controller, $method, $request_type=7) {
$this->routes[] = array("route" => $route, "call" => array($controller, $method), "request_type" => 7);
}
public function route($str) {
foreach ($this->routes as $v) {
// Do your request_type match here. Exercise left for the reader!
if (preg_match($str, $v['route'], $matches)) {
try {
$controller = IoC::instance($v['call'][0]);
if (!method_exists($controller, $v['call'][1])) throw new Exception("Method not found: ".$v['call'][1]);
array_shift($matches);
call_user_func_array(array($controller,$v['call'][1]), $matches);
} catch (Exception $e) {
}
}
}
}
}
那是你的路由器!您可能想知道为什么 IoC
是纯粹的静态类,而 Router
是实例化的。原因很简单:您可能希望您的模块拥有自己的子路由器,而不必总是处理一个路由器。我经常这样做,这使我能够完全划分我的 PAC 结构并构建逻辑路由层次结构。
这就是所有的路由!从前面看,您的框架代码现在如下所示:
IoC::register("controller1","My\\Controller");
$router = new Router();
$router->register(...);
$router->route($_SERVER['QUERY_STRING']);
不错,简洁,抽象化了所有问题!由此,您可以构建遵循 MVC 架构或其任何变体的框架。这对于 PAC 来说效果非常好。
关于php - 创建 PHP 'controller' 文件来构建网站上的所有页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16843004/