2

我正在使用 CodeIgniter 框架开发另一个项目,该框架有一个主控制器文件,用于构建网站上的所有页面。

输入诸如“domain.com/about”之类的 url 将在控制器文件中运行“function about(){”,该文件加载到该页面的各个组件中。

这其中的大部分魔法都是由 CodeIgniter 或其他项目成员处理的,所以我不确定这是如何发生的。

我希望在不使用任何框架的情况下实现相同的目标,并且完全不知道如何完成它。我知道我可以在“domain.com?load=about”的某处有一个 url,并使用它来运行该功能,但我希望该 URL 干净,便于访问者访问输入。

所以,我的问题是..如何设置我的网站,使其始终指向单个文件“controller.php”,然后运行与 URL 中输入的内容匹配的函数,并且该 URL 不是直接的我远离控制器页面?(也就是说,如果我输入 'domain.com/about' 我不想被带到 about.php 页面!)

如果这个问题难以理解,或者我对任何事情采取了错误的方法,我提前道歉。也因为缺乏例子和描述..我真的不知道更具体。如果您有什么需要看或知道的,尽管问,我会尽力澄清!

谢谢!

4

3 回答 3

2

您对此没有很多好的答案。让我们添加更多细节。

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();
          }
      }
 }

这有很多好处:

  • 您很可能有一天会决定将控制器更改为Controller2from 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 一起工作得非常好。

于 2013-05-30T19:12:37.520 回答
2

好的,您似乎正在使用 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 和 $URI_parts[1] = my_product_item

这是一个非常基本的开始。希望它可以帮助您进一步构建。

我会推荐你​​使用一个框架。例如无脂肪框架 (F3)。你还有其他人。所以由你决定。

于 2013-05-30T18:23:54.573 回答
-1

为此,您需要将所有流量重定向到您的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(类)。这样做将使您拥有公共/私人功能,并允许您拥有更复杂的网址,例如 www.example.com/items/12。当然,您仍然希望确保该方法可用。为此,您可以使用 PHP 的method_exists函数。

于 2013-05-30T18:15:23.747 回答