紫郢青索

知之者不如好之者,好之者不如乐之者

用户工具

站点工具


PHP实现派发器

首先,我们来看下,刚开始学习php做web开发时,通常会用这两种方式组织文件。

一种是

  • 文章分类 - 我们写了一个文件 category.php
  • 文章列表 - 我们写一个文件 list.php
  • 文章内容 - 我们写一个文件 detail.php

代码举例

category.php
  <?php
    echo "category";
  ?>
list.php
  <?php
    echo "list";
  ?>
detail.php
  <?php
    echo "detail";
  ?>

另一种

  • 文章分类、列表、内容 - 我们写一个文件中 article.php。然后通过参数 page 判断执行不同的逻辑。
  • page = category, 处理文章分类
  • page = list, 处理文章列表
  • page = detail, 处理文章内容。

代码举例

article.php
  <?php
    $page = $_GET['page'];
    if($page == 'category'){
        echo "category";
    }else if($page == 'list'){
        echo "category";
    }else if($page == 'detail'){
        echo "category";
    }
  ?>

我们设计一个统一入口的派发器

我们要实现的是这样的一个派发器。

通过约定一个url请求的规则来分发请求。

URL规则为: baseURL/{controller}/{action}?param1=val1&param2=val2 …

  • 分发到PHP文件: basePath/controller/{controller}Controller.php
  • 并执行该文件中定义的类 {controller}Controller 的方法 {action}Action()

我们看下这个派发器的代码

Dispatcher.php
<?php
/**
 * 派发器
 */
namespace core;
use controller;
 
class Dispatcher{
    // 配置参数
    // 配置默认的控制器 和 默认的执行方法
    public static $config = array(
        'defaultController' => 'IndexController',
        'defaultAction' => 'defaultAction',
        'controllerPath' => '',
        'modelPath' => '',
    );
    // 将请求中的 /param1/val1/param2/val2 ...  转换此行是的参数为字典形式。
    public static $params = array();
    // 定义派发器实例
    private static $_instance = null;
    public static $log = null;
 
    /**
     * Dispatcher constructor.
     */
    private function __construct()
    {
 
    }
 
    /**
     * @param $config
     */
    public function config($config)
    {
        if (!empty($config)) {
            require_once $config;
        }
        self::$config = array_merge(self::$config, $config);
    }
 
    /**
     * 单例模式 实例
     * Singleton instance
     *
     * @return Dispatcher
     */
    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }
 
        return self::$_instance;
    }
 
    /**
     * 启动派发器
     * @throws Exception
     */
    public function start()
    {
        // baseURL/{controller}/{action}
        // 获取请求的 PATH_INFO
        $pathInfo = isset($_SERVER['PATH_INFO']) ? trim($_SERVER['PATH_INFO'],'/') : '';
        $dispatchInfo = array();
        // 解析出 controller 和 action 
        $tmp = explode('/', $pathInfo);
        $dispatchInfo['controller'] = 'controller\\'.(($controller = current($tmp)) ? ucfirst($controller) . "Controller" : self::$config['defaultController']);
        $dispatchInfo['action'] = ($action = next($tmp)) ? $action . 'Action' : self::$config['defaultAction'];
 
        // 将请求中的 /param1/val1/param2/val2 ...  转换此行是的参数为字典形式。
        $params = array();
        while (false !== ($next = next($tmp))) {
            $params[$next] = urldecode(next($tmp));
        }
        Dispatcher::$params = $params;
 
        extract($dispatchInfo);
        // 获取控制器实例
        if (isset($controller)) {
            if(!class_exists($controller)){
                throw new Exception("Can't find controller:{$controller}");
            }
            $ctl = new $controller();
        }
 
        // 执行当前控制器实例 的 方法
        if (isset($action)) {
            $func = isset($ctl) ? array($ctl, $action) : $action;
            if (!is_callable($func, true)) {
                throw new Exception("Can't dispatch action:{$action}");
            }
            call_user_func($func);
        }
    }
}

关键的方法是 start()。 使用的前面PHP基础中讲到的 可变函数