/** * Matches a route and HTTP method/s against the request path, and if successful, invokes a controller and **exits**. * * When a route and method/s are matched, the HTTP response code is automatically set to `200`. * The controller is then invoked and responsible for the response code from then on. * * Otherwise a response code of either `404` or `405` is set. * * This also means that within a subrouter the HTTP response can go from an initial `200` to `404`/`405` if those subroutes fail. * * To allow safe fallthrough, a `404` response code will not replace an existing `405`. * * @param string[] $methods HTTP request methods, or empty to accept any method. * @param string $route A literal path with leading slash, or a regular expression. * Regular expressions are enclosed by anything other than a slash, since slashes are used for literal paths. * @param callable $controller Given either the [preg_match()](http://php.net/preg-match) array, or the literal path. * The controller can output content directly if it chooses, but it must also output headers and **exit**. * If not, the return value is given to {@link \H\O::mixed()}, which **exits**. */ public static function route($methods, $route, callable $controller) { $match = $path = I::path(); if ($route === $path or $route[0] !== '/' && preg_match($route, $path, $match)) { if (empty($methods) or in_array(I::method(), $methods)) { O::code(200); O::mixed(call_user_func($controller, $match)); // exits } else { O::code(405); } } elseif (O::code() !== 405) { O::code(404); } }