您对此没有很多好的答案。让我们添加更多细节。
CodeIgniter 的工作原理
网址路由
CodeIgniter 的第一步实际上是在 CodeIgniter 本身之外完成的。您将在 HTTP 守护程序中找到此步骤。如果是 Apache,你会看到类似这样的重写规则:
RewriteRule ^(.+)$ /index.php?$1 [L]
如果你正在运行 nginx,你会看到:
rewrite ^/(.+)$ /index.php?/$1 last;
这是每个框架的核心指令之一,将导致它处理和解析每个请求(基于RewriteCond
/try_files
指令,可能包含找到或不包含的文件)。用户提供的查询字符串将在$_SERVER['QUERY_STRING']
. 请记住这一点,我们将不止一次地回到这一点。
进入框架
如果您计划构建一个框架,您的框架应该具有称为Router的功能。这是一个简洁的小类(或类集合),它将处理路由的动态创建。路由是 URI(可能包含通配符)和控制器功能(或多个功能)之间的定向映射。
第一次编写自己的框架的人经常忽略这一点,并且可以在有效的东西和使用起来非常痛苦的东西之间产生差异(PHP 的差异很小。这在其他技术上确实很明显)。
所以。一个路由器。获取路线列表,将它们转换为类和函数。我们想要缓存我们的控制器并提供它们的动态分配,所以我们将带来一个新概念:控制反转。如果您使用过更新的框架(Kohona、Laravel 等),您会对此很熟悉。实际上,它允许您将类名绑定到 go-to 字符串并通过中介控制此类类的实例化(从而遵循好莱坞原则 - 您请求控制器,您不实例化它)。
经典的 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();
}
}
}
这有很多好处:
- 您很可能有一天会决定将控制器更改为
Controller2
from Controller1
。通过使用IoC
包装器来解决它,您可以为自己节省一些痛苦 - 不必遍历整个代码
- 原生处理
Singletons
,不会使它们难以进行单元测试
所以。凭借我们的知识,我们现在可以使用我们选择的任意关键字来实例化一个类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 一起工作得非常好。