我正在使用CodeIgniter框架进行另一个项目,该框架有一个主控制器文件,用于构建站点上的所有页面。
输入url,如'domain.com/about',将在控制器文件中运行'function about(){',该文件将加载该页面的各个组件。
大部分的魔法是由CodeIgniter或其他项目成员处理的,所以我不确定这是如何发生的。
我希望实现同样的事情,而不使用任何框架,我完全不知道如何完成它。我知道我可以在'domain.com?load=about'的某个地方有一个url,并使用它来运行该函数,但我希望url干净,便于访问者输入。
所以,我的问题是……我怎么能设置我的网站,使它始终指向一个文件,'控制器。php',然后运行的函数匹配什么是在URL中输入,并有该URL不直接我远离控制器页面?(也就是说,如果我输入'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(可能包含通配符)和控制器函数(或多个函数)之间的方向映射。
这一点经常被第一次编写框架的人所忽视,这可能会导致一些东西可以工作,而一些东西使用起来非常痛苦(在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();
}
}
}
这有很多好处:
- 你很可能有一天决定把你的控制器从
Controller1
改为Controller2
。通过使用IoC
包装器来解决这个问题,您省去了一些麻烦—不必遍历整个代码 - 原生处理
Singletons
,而不会使它们难以进行单元测试
。凭借我们的知识,我们现在可以使用IoC::instance("ourkeyword");
基于我们选择的任意关键字实例化一个类。我们会经常用到这个。首先,有一个警告:这个IoC包装器假定您将使用spl_autolload来惰性加载您的类。
路由器本身应该是这样的:
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体系结构或其任何变体的框架。
似乎你正在使用PHP。这意味着,很可能您将使用Apache web服务器。在。htaccess中,可以有
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule .* index.php [L,QSA]
</IfModule>
你所有的请求都将被重定向到你的主控制器index.php。
在index。php中,有
$URI_parsed = parse_url($_SERVER['REQUEST_URI']);
$URI_parts = explode('/', $URI_parsed['path']);
您现在可以使用$URI_parts来决定要做什么。示例
if ($URI_parts[0] == 'about')
about();
如果你对变量函数很熟悉,那么也许
$func = $URI_parts[0];
$func();
在任何情况下,你必须处理$URI_parts[x](其中x> 0),例如URL是
www.mydomain.com/products/my_product_item
在本例中$URI_parts[0] = products and $URI_parts[1] = my_product_item
这是一个非常基本的开始。希望它能帮助你更进一步。
我建议您使用框架。例如,无脂肪框架(F3)。你还有其他人。所以由你来决定。
要做到这一点,您需要将所有流量重定向到您的controller
主页面。您可以使用Apache的mod_rewrite
模块或IIS的web.config
文件(对于较低版本的IIS,您需要查看mod_rewrite
模块)来完成此操作。使用这些,您可以将漂亮的url转换为程序更容易识别的内容。如何做到这一点取决于您的实现。根据你的解释,你可以这样做:
$action = 'index'; //Used for first visiting the site
if(isset($_GET['action'])) {
$action = $_GET['action'];
}
if(function_exists($action)) {
$action();
}
else {
//Display 404 error
}
现在,这是一个非常简单的例子,但将做你在你的帖子中描述的。
如果你要做一些更复杂的事情,你可以把你的代码分成多个文件,并使用OOP(类)。这样做将允许您拥有公共/私有函数,并允许您拥有更复杂的url,例如www.example.com/items/12。当然,您仍然希望确保该方法可用。为此,可以使用PHP的method_exists函数。