Just for fun——PHP 框架之简单的路由器(1)

路由#

路由的功能就是分发请求到不同的控制器,基于的原理就是正则匹配。接下来呢,我们实现一个简单的路由器,实现的能力是

  1. 对于静态的路由(没占位符的),正确调用 callback
  2. 对于有占位符的路由,正确调用 callback 时传入占位符参数,譬如对于路由:/user/{id},当请求为 /user/23 时,传入参数 $args 结构为
    [
    'id' => '23'
    ]

    大致思路#

  3. 我们需要把每个路由的信息管理起来:http 方法($method),路由字符串($route),回调($callback),因此需要一个 addRoute 方法,另外提供短方法 get,post(就是把 $method 写好)
  4. 对于 /user/{id} 这样的有占位符的路由字符串,把占位符要提取出来,然后占位符部分变成正则字符串

实现#

Route.php 类#

<?php

namespace SalamanderRoute;

class Route {
    /** @var string */
    public $httpMethod;

    /** @var string */
    public $regex;

    /** @var array */
    public $variables;

    /** @var mixed */
    public $handler;

    /**
     * Constructs a route (value object).
     *
     * @param string $httpMethod
     * @param mixed  $handler
     * @param string $regex
     * @param array  $variables
     */
    public function __construct($httpMethod, $handler, $regex, $variables) {
        $this->httpMethod = $httpMethod;
        $this->handler = $handler;
        $this->regex = $regex;
        $this->variables = $variables;
    }

    /**
     * Tests whether this route matches the given string.
     *
     * @param string $str
     *
     * @return bool
     */
    public function matches($str) {
        $regex = '~^' . $this->regex . '$~';
        return (bool) preg_match($regex, $str);
    }

}

Dispatcher.php#

代码已被折叠,点此展开

配置#

nginx.conf 重写到 index.php#

location / {
        try_files $uri $uri/ /index.php$is_args$args;

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

    }

composer.json 自动载入#

{
    "name": "salmander/route",
    "require": {},
    "autoload": {
      "psr-4": {
        "SalamanderRoute\\": "SalamanderRoute/"
      }
  }
}

最终使用#

index.php#

<?php

include_once 'vendor/autoload.php';

use SalamanderRoute\Dispatcher;

$dispatcher = new Dispatcher();

$dispatcher->get('/', function () {
    echo 'hello world';
});

$dispatcher->get('/user/{id}', function ($args) {
    echo "user {$args['id']} visit";
});

// Fetch method and URI from somewhere
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];

// 去掉查询字符串
if (false !== $pos = strpos($uri, '?')) {
    $uri = substr($uri, 0, $pos);
}

$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
    case Dispatcher::NOT_FOUND:
        echo '404 not found';
        break;
    case Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        $handler($vars);
        break;
}

clipboard.png

clipboard.png

代码讲解,未完待续 ^--^#

我的专栏

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。