创建PHP '控制器'文件构建站点上的所有页面


Creating a PHP 'controller' file to build all pages on site

我正在使用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函数。