单一入口,根据uri解析路由

96
小龙123
2019.04.17 15:24* 字数 150

在做单一入口的时候,根据URI 对应的参数设置路由和控制器

  • 思路 xx.com/index/index?name=test&age=22

将斜杠后面的第一个参数赋值为控制器,第二个参数赋值为控制器中的方法,
?后面的参数不需要处理,直接 _GET 即可获取到 如果没有传递方法参数,则使用默认的参数,要注意控制器或者方法的参数里面有没有问号,即_GET 参数,比如 xx.com/index?name=test&age=22,要做好处理,遇到问号,就直接返回即可

<?php

namespace Core\Lib;

/**
 * 路由类
 * Class Route
 * @package Core\Lib
 */
class Route
{
    /**
     * @var string  控制器名   默认是 indexController
     */
    public $controller = 'indexController';

    /**
     * @var string  方法名  默认是 index
     */
    public $action = 'index';

    /**
     *  xx.com/index/index
     *  支持两种传参方式  如果传参,则必须写全控制器与方法
     * Route constructor.
     */
    public function __construct()
    {
        // $_SERVER['REQUEST_URI'] 这个值其实是一定会出现的,如果 url 只有站点,则显示 '/',代表访问首页
        if (in_array($_SERVER['REQUEST_URI'], ['/', '/index.php'])) {
            return true;
        }
        //  如果不在 ['/', '/index.php'],则代表肯定有值
        $arr = explode('/', trim($_SERVER['REQUEST_URI'], '/'));
        // /  后的第一个参数是控制器名
        if (isset($arr[0])) {
            if (mb_strpos($arr[0], '?') !== false) {
                list($controller, $request_get) = explode('?', $arr[0]);
                $this->controller = $controller. 'Controller';
                // 如果有问号,则表示使用的默认控制器和方法
                return true;
            }
            $this->controller = $arr[0] . 'Controller';
        }
        unset($arr[0]);
        // 第二个参数是控制器方法
        if (isset($arr[1])) {
            if (mb_strpos($arr[1], '?') !== false) {
                list($method, $request_get) = explode('?', $arr[1]);
                $this->action = $method;
                //  表示有问号传值
                return true;
            } else {
                $this->action = $arr[1];
            }
        }
        // 第三个参数是 回调对应的 Service ,是哦自己项目中使用到的一个参数值
        if (isset($arr[2])) {
            if (mb_strpos($arr[2], '?') !== false) {
                //  表示有问号传值
                list($service, $request_get) = explode('?', $arr[2]);
                $_ENV['service'] = $service;
            } else {
                $_ENV['service'] = $arr[2];
            }
        }

// 以下方式是设置成 /key/value 的这种形式的。
//        if (!$_GET) {
//            //  如果使用 ?  方式传递参数,则不再处理
//            unset($arr[1]);
//            // url 多余部分转换成 get 参数  index/index/id/1
//            // 重新获取控制器和方法以外的参数,奇数是值,奇数加1是键,
//            $i = 2;
//            while (isset($arr[$i])) {
//                if (!isset($arr[$i + 1])) {
//                    //  不存在这个键,则肯定到此为止了
//                    $get_values[$arr[$i]] = '';
//                    break;
//                }
//                $_GET[$arr[$i]] = $arr[$i + 1];
//                $i = $i + 2;
//            }
//        }

    }

}

应用

     // 获取路由
        $route = new Route();
        // 2.判断控制器是否存在
        $class = '/App/Controller/' . $route->controller;
        if (!is_file(BASE_PATH . $class . '.php')) {
            self::responseError('路由不存在', -401);
        }

        $class = str_replace('/', '\\', $class);
        $controller = new  $class();
        //  3.判断控制器中的方法是否存在
        $action = $route->action;
        if (!method_exists($controller, $action)) {
            self::responseError('路由不存在', -402);
        }

        // 4. 请求控制器中的方法
        $response = call_user_func([$controller, $route->action]);
        // 正常返回肯定是数组形式,不会执行到这一步
        if (!is_array($response)) {
            self::responseError('返回数据格式有误,请联系客服,谢谢!', -501);
        }
        //  如果 返回的是 responseError  status !==200 则表示返回有误,记录错误日志   回调中有可能没有 status 状态
        $response['status'] = isset($response['status']) ? $response['status'] : -10001;
        if ($response['status'] !== 200) {
            app_log($response, Log::LOG_RESPONSE_ERROR);
        }

        echo json_encode($response, JSON_UNESCAPED_UNICODE);
        die;

使用 composer 实现自动加载即可,不需要自己再使用 spl_autoload_register()函数
composer.json

{
  "autoload": {
    "psr-4": {
      "App\\": "app/",
      "Core\\": "core/"
    },
    "files": [
      "core/common/function.php"
    ]
  }
}

执行 composer autoload

PHP
Web note ad 1