(5)路由的抽象与实现

发布于:2022-08-24 12:03:49

一、入口文件(index.php)

地址栏访问:http://localhost/index.php/get


<?php

define('APP_PATH', dirname(__DIR__) . ''); //定义APP主目录,用于自动加载,后期引入composer后可以省略
define('VIEW_PATH', dirname(__DIR__) . '/view'); //定义视图主目录,用于控制器加载视图,后期改为display方法后可以省略

include_once '../core/autoload.php';
include_once '../cnf/router.php'; //引用路由文件

(new core\core())->start();

二、自动加载器(autoload.php)


<?php

class autoload
{
    /**
     * 自动加载
     */
    public static function loader($class)
    {
        // var_dump($class);
        if (false !== strpos($class, '\\')) { //用户类不以\开头
            $filename = str_replace('\\', '/', $class) . '.php'; //引入命名空间后,传入的参数$class包含完整的命名空间和类名,此处替换\为/并加上.php结尾,用于include原始文件
            $FirstNamespace = substr($filename, 0, strpos($filename, '/')); //获取命名空间的第一段,一般用这种方法对应空间主目录
            switch ($FirstNamespace) {
                case 'core':
                    $filename = dirname(__DIR__) . '/' . $filename; //core目录目前与autoload在同一目录下,用这种方式拼接出完整目录
                    break;
                case 'app':
                    $filename = APP_PATH . '/' . $filename; //core目录目前与autoload在同一目录下,用这种方式拼接出完整目录
                    break;
                default:
                    $filename = dirname(__DIR__)  . '/' . $filename; //默认的加载目录,后边再改造
            }
            // print_r(is_file($filename) . '====' . $class . '====' . $filename . PHP_EOL);
            if (is_file($filename)) {
                include $filename; //加载文件,自动加载的核心
            }
        }
    }
}

spl_autoload_register(array('autoload', 'loader'), true);//参考:https://www.php.net/manual/zh/function.spl-autoload-register.php

三、核心类(core.php)


<?

namespace core;

class core
{

    public function start()
    {
        $cf = router::findRouter(); //寻找路由
        if (!$cf) {
            throw new \Exception('路由不存在');
        }

        $c = $cf[0];
        if (!class_exists($c)) { //判断路由对应的类是否存在
            throw new \Exception('路由类不存在');
        }
        $obj = new $c(); //初始化对象
        $func = $cf[1];
        return $obj->$func(); //根据路由调用对象的方法
    }
}

四、路由类(router.php)


<?

namespace core;

use Exception;

class router
{
    public static  $Routers;

    public static function findRouter()
    {
        $uri = $_SERVER['REQUEST_URI']; //重点,在web模式下,使用REQUEST_URI作为路由的匹配条件,REQUEST_URI一般为/后的部分,例日"http://www.xxx.com/aaa/bbb",此时REQUEST_URI="/aaa/bbb"
        foreach (self::$Routers as $router) { //循环所有的路由,注意此处尚未对get、post等请求进行路由区分
            foreach ($router as $route => $class_function) {
                if (preg_match($route, $uri, $matches)) { //按照正则模式对路由进行匹配,即'/aaa/bbb'与注册的路由的第一个参数进行正则匹配,匹配上即使用第二个第三个参数指定的类处理请求。
                    return [$class_function[0], $class_function[1]]; //将寻找到的路由返回给core
                }
            }
        }
        return false;
    }

    ///////////////////以下方法用于注册路由///////////////////
    public static function registerRouter($type, $router, $class, $func)
    {
        self::$Routers[$type][$router] = [$class, $func];
    }
    /**
     * php内置的静态方法,当调用本类的一个不存在的静态方法时,调用此方法,将方法名和参数传入此函数
     * 用于实现类似router::get(),router::post()等路由设置的统一调用
     * 参考文档:https://www.php.net/manual/zh/language.oop5.overloading.php#object.callstatic
     */
    public static function __callStatic($name, $args)
    {
        $type = strtolower($name); //被调用函数小写
        if (!$args[0]) {
            throw new Exception('未设置路由');
        }
        $router = $args[0];
        $class = isset($args[1]) ? $args[1] : 'app\\index';
        $func = isset($args[2]) ? $args[2] : 'index';
        self::registerRouter($type, $router, $class, $func);
    }
}

五、路由配置(router.php)


<?php

use core\router;

router::get('/get/', 'app\\app', 'getTest');
router::post('/post/', 'app\\app', 'postTest');

六、引用控制器和视图

1、控制器app.php


<?php

namespace app;

class app
{

    public function getTest()
    {
        $name = "开发者";
        include VIEW_PATH . '/app/index.php';
    }
    public function postTest()
    {
        echo '我是服务器返回的post内容,返回时间时:' . date('Y-m-d H:i:s');
    }
}

2、视图view.php


<html>

<head>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>

<body>
    <h2>你好<?php echo $name; ?></h2>
    <div id="text" style="width:300px;height:100px;"></div>
    <button id="btn">测试post</button>
    <script type="text/javascript">
        $("#btn").click(function() {
            $.post('/index.php/post', {
                name: "我是服务器"
            }, function(data) {
                $("#text").html(data);
            })

        })
    </script>
</body>

</html>

七、目录及效果图


效果图


附件:点击下载
阅读 449