The function of routing is to distribute requests to different controllers, based on the principle of regular matching. Next, we implement a simple router, the ability to implement is for static routing (no placeholder), the correct call to callback.
For routes with placeholders, when callback is called correctly, a placeholder parameter is passed in, such as for route:/user/{id} When the request is/USER/23, the incoming parameter $args structure is
[ ' id ' = ' 23 ']
General idea
We need to manage the information for each route: the HTTP method ($method), the routing string ($route), the callback ($callback), so a Addroute method is required, and a short method is provided get,post (that is, write $method).
For a placeholder-like routing string such as/user/{id}, the placeholder is extracted and the placeholder part becomes a regular string
Realize
Route.php class
<?phpnamespace salamanderroute;class Route {/** @var String */Public $http Method; /** @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 = $httpMetho D $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
<?php/** * User:salamander * DATE:2017/11/12 * time:13:43 */namespace salamanderroute;class Dispatcher {/** @var mixed[][] */protected $staticRoutes = []; /** @var route[][] */private $METHODTOREGEXTOROUTESMAP = []; Const NOT_FOUND = 0; Const FOUND = 1; Const METHOD_NOT_ALLOWED = 2; /** * Extract Placeholder * @param $route * @return Array */Private Function Parse ($route) {$regex = ' ~^ (?:/ [A-za-z0-9_]*|/\{([a-za-z0-9_]+?) \})+/?$~'; if (Preg_match ($regex, $route, $matches)) {//Remove full match array_shift ($matches); return [Preg_replace (' ~{[a-za-z0-9_]+?} ~ ', ' ([a-za-z0-9_]+) ', $route), $matches,]; } throw new \logicexception (' Register route failed, pattern is illegal '); }/** * Register routing * @param $httpMethod string | string[] * @param $route * @param $handler */Public Function Addroute ($httpMethod, $route, $handler) { $routeData = $this->parse ($route); foreach ((array) $httpMethod as $method) {if ($this->isstaticroute ($routeData)) {$this Addstaticroute ($httpMethod, $routeData, $handler); } else {$this->addvariableroute ($httpMethod, $routeData, $handler); }}} Private Function Isstaticroute ($routeData) {return count ($routeData [1]) = = = 0; } Private Function Addstaticroute ($httpMethod, $routeData, $handler) {$routeStr = $routeData [0]; if (Isset ($this->staticroutes[$httpMethod [$routeStr])) {throw new \logicexception (sprintf ( ' Cannot register routes matching '%s ' for method '%s ', $routeStr, $httpMethod); } if (Isset ($this->methodtoregextoroutesmap[$httpMethod])) {foreach ($this->methodtoregextoroutes map[$httpMethod] as $route) {if ($route->matches ($routeStr)) { throw new \logicexception (sprintf (' Static route '%s ' is shadowed by previously D efined variable route '%s ' for method '%s ', $routeStr, $route->regex, $httpMethod )); }}} $this->staticroutes[$httpMethod] [$routeStr] = $handler; } Private Function Addvariableroute ($httpMethod, $routeData, $handler) {list ($regex, $variables) = $routeData; if (Isset ($this->methodtoregextoroutesmap[$httpMethod [$regex])) {throw new \logicexception (sprintf ( ' Cannot register routes matching '%s ' for method '%s ', $regex, $httpMethod )); } $this->methodtoregextoroutesmap[$httpMethod [$regex] = new Route ($httpMethod, $handler, $regex, $v Ariables); Public function Get ($route, $handler) {$this->addroute (' Get ', $route, $handler); } public FunctIon Post ($route, $handler) {$this->addroute (' Post ', $route, $handler); The public function put ($route, $handler) {$this->addroute (' Put ', $route, $handler); Public Function Delete ($route, $handler) {$this->addroute (' delete ', $route, $handler); Public function patch ($route, $handler) {$this->addroute (' Patch ', $route, $handler); The Public function head ($route, $handler) {$this->addroute (' head ', $route, $handler); /** * Distribution * @param $httpMethod * @param $uri */Public Function dispatch ($httpMethod, $uri) { $staticRoutes = Array_keys ($this->staticroutes[$httpMethod]); foreach ($staticRoutes as $staticRoute) {if ($staticRoute = = = $uri) {return [Self::found, $this ->staticroutes[$httpMethod] [$staticRoute], []]; }} $routeLookup = []; $index = 1; $regexes = Array_keys ($this->methodtoregextoroutesmap[$htTpmethod]); foreach ($regexes as $regex) {$routeLookup [$index] = [$this->methodtoregextoroutesmap[$http method][$regex]->handler, $this->methodtoregextoroutesmap[$httpMethod] [$regex]->variables, ]; $index + = count ($this->methodtoregextoroutesmap[$httpMethod] [$regex]->variables); } $regexCombined = ' ~^ (?: '. Implode (' | ', $regexes). ')$~'; if (!preg_match ($regexCombined, $uri, $matches)) {return [self::not_found]; } for ($i = 1; "= = = $matches [$i]; + + $i); List ($handler, $varNames) = $routeLookup [$i]; $vars = []; foreach ($varNames as $varName) {$vars [$varName] = $matches [$i + +]; } return [Self::found, $handler, $vars]; }}
Configuration
nginx.conf Rewrite to 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$ {FASTCG I_pass 127.0.0.1:9000; Fastcgi_index index.php; Fastcgi_param script_filename $document _root$fastcgi_script_name; Include Fastcgi_params; }}composer.json automatically load {"name": "Salmander/route", "require": {}, "AutoLoad": {"psr-4": {"Salamand Erroute\\ ":" Salamanderroute/"}}}
Composer.json Automatic loading
{ "name": "Salmander/route", "require": {}, "AutoLoad": { "psr-4": { "salamanderroute\\": " salamanderroute/" } }
End Use
index.php
<?phpinclude_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 '];//remove query string 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;}
Look at the above case we should implement a simple router for PHP, have a clearer understanding of it, later we will continue to launch relevant articles, we have any questions can be enthusiastic to speak,