{"id":13405188,"url":"https://github.com/miladrahimi/phprouter","last_synced_at":"2026-01-11T16:47:04.763Z","repository":{"id":32959037,"uuid":"36563563","full_name":"miladrahimi/phprouter","owner":"miladrahimi","description":"PhpRouter is a full-featured yet very fast HTTP URL router for PHP projects","archived":false,"fork":false,"pushed_at":"2024-08-19T12:41:37.000Z","size":351,"stargazers_count":191,"open_issues_count":2,"forks_count":17,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-09-20T06:11:08.657Z","etag":null,"topics":["http-router","http-routing","php","php-router","php-router-standalone","php-routing","phprouter","psr-7","router","routing","url-router","url-routing"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/miladrahimi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"miladrahimi","custom":["https://miladrahimi.com/pay.html","https://www.paypal.com/paypalme/realmiladrahimi"]}},"created_at":"2015-05-30T15:24:30.000Z","updated_at":"2024-09-16T12:02:29.000Z","dependencies_parsed_at":"2024-01-18T23:04:51.501Z","dependency_job_id":"8631a291-946b-4d7a-9523-134f33ff7be7","html_url":"https://github.com/miladrahimi/phprouter","commit_stats":{"total_commits":251,"total_committers":7,"mean_commits":"35.857142857142854","dds":0.4143426294820717,"last_synced_commit":"2d394bd4df6c10e066481ae29aa545e552df012a"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miladrahimi%2Fphprouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miladrahimi%2Fphprouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miladrahimi%2Fphprouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miladrahimi%2Fphprouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/miladrahimi","download_url":"https://codeload.github.com/miladrahimi/phprouter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221454077,"owners_count":16824598,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http-router","http-routing","php","php-router","php-router-standalone","php-routing","phprouter","psr-7","router","routing","url-router","url-routing"],"created_at":"2024-07-30T19:01:57.099Z","updated_at":"2026-01-11T16:47:04.756Z","avatar_url":"https://github.com/miladrahimi.png","language":"PHP","funding_links":["https://github.com/sponsors/miladrahimi","https://miladrahimi.com/pay.html","https://www.paypal.com/paypalme/realmiladrahimi"],"categories":["PHP"],"sub_categories":[],"readme":"[![Latest Stable Version](https://poser.pugx.org/miladrahimi/phprouter/v)](//packagist.org/packages/miladrahimi/phprouter)\n[![Total Downloads](https://poser.pugx.org/miladrahimi/phprouter/downloads)](//packagist.org/packages/miladrahimi/phprouter)\n[![Build](https://github.com/miladrahimi/phprouter/actions/workflows/ci.yml/badge.svg)](https://github.com/miladrahimi/phprouter/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/miladrahimi/phprouter/graph/badge.svg?token=KctrYUweFd)](https://codecov.io/gh/miladrahimi/phprouter)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/miladrahimi/phprouter/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/miladrahimi/phprouter/?branch=master)\n[![License](https://poser.pugx.org/miladrahimi/phprouter/license)](//packagist.org/packages/miladrahimi/phprouter)\n\n# PhpRouter\n\nPhpRouter is a full-featured yet very fast HTTP URL router for PHP projects.\n\nSome of the provided features:\n* Route parameters\n* Predefined route parameter patterns\n* Middleware\n* Closure and class controllers/middleware\n* Route groups (by prefix, middleware, and domain)\n* Route naming (and generating route by name)\n* PSR-7 requests and responses\n* Views (simple PHP/HTML views)\n* Multiple (sub)domains (using regex patterns)\n* Custom HTTP methods\n* Integrated with an IoC Container ([PhpContainer](https://github.com/miladrahimi/phpcontainer))\n* Method and constructor auto-injection of Request, Route, Url, etc\n\nThe current version requires PHP `v8.0` or newer versions.\n\n## Contents\n- [Versions](#versions)\n- [Documentation](#documentation)\n    - [Installation](#installation)\n    - [Configuration](#configuration)\n    - [Getting Started](#getting-started)\n    - [HTTP Methods](#http-methods)\n    - [Controllers](#controllers)\n    - [Route Parameters](#route-parameters)\n    - [Requests and Responses](#requests-and-responses)\n    - [Views](#views)\n    - [Route Groups](#route-groups)\n    - [Middleware](#middleware)\n    - [Domains and Subdomains](#domains-and-subdomains)\n    - [Route Names](#route-names)\n    - [Current Route](#current-route)\n    - [Error Handling](#error-handling)\n- [License](#license)\n\n## Versions\n* **v5.x.x** (Current, Supported)\n* v4.x.x\n* v3.x.x\n* v2.x.x\n* v1.x.x\n\n## Documentation\n\n### Installation\n\nInstall [Composer](https://getcomposer.org) and run following command in your project's root directory:\n\n```bash\ncomposer require miladrahimi/phprouter \"5.*\"\n```\n\n### Configuration\n\nFirst of all,\nyou need to configure your webserver to handle all the HTTP requests with a single PHP file like the `index.php` file.\nHere you can see sample configurations for NGINX and Apache HTTP Server.\n\n* NGINX configuration sample:\n    ```nginx\n    location / {\n        try_files $uri $uri/ /index.php?$query_string;\n    }\n    ```\n\n* Apache `.htaccess` sample:\n    ```apacheconfig\n    \u003cIfModule mod_rewrite.c\u003e\n        \u003cIfModule mod_negotiation.c\u003e\n            Options -MultiViews\n        \u003c/IfModule\u003e\n\n        RewriteEngine On\n\n        RewriteCond %{REQUEST_FILENAME} !-d\n        RewriteRule ^(.*)/$ /$1 [L,R=301]\n\n        RewriteCond %{REQUEST_FILENAME} !-d\n        RewriteCond %{REQUEST_FILENAME} !-f\n        RewriteRule ^ index.php [L]\n    \u003c/IfModule\u003e\n    ```\n\n### Getting Started\n\nIt's so easy to work with PhpRouter! Just take a look at the following example.\n\n*  JSON API Example:\n\n    ```php\n    use MiladRahimi\\PhpRouter\\Router;\n    use Laminas\\Diactoros\\Response\\JsonResponse;\n\n    $router = Router::create();\n\n    $router-\u003eget('/', function () {\n        return new JsonResponse(['message' =\u003e 'ok']);\n    });\n\n    $router-\u003edispatch();\n    ```\n\n* View Example:\n\n    ```php\n    use MiladRahimi\\PhpRouter\\Router;\n    use MiladRahimi\\PhpRouter\\View\\View\n\n    $router = Router::create();\n    $router-\u003esetupView('/../views');\n\n    $router-\u003eget('/', function (View $view) {\n        return $view-\u003emake('profile', ['user' =\u003e 'Jack']);\n    });\n\n    $router-\u003edispatch();\n    ```\n\n### HTTP Methods\n\nThe following example illustrates how to declare different routes for different HTTP methods.\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\n\n$router = Router::create();\n\n$router-\u003eget('/', function () { /* ... */ });\n$router-\u003epost('/', function () { /* ... */ });\n$router-\u003eput('/', function () { /* ... */ });\n$router-\u003epatch('/', function () { /* ... */ });\n$router-\u003edelete('/', function () { /* ... */ });\n\n$router-\u003edispatch();\n```\n\nYou can use the `define()` method for other HTTP methods like this example:\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\n\n$router = Router::create();\n\n$router-\u003edefine('GET', '/', function () { /* ... */ });\n$router-\u003edefine('OPTIONS', '/', function () { /* ... */ });\n$router-\u003edefine('CUSTOM', '/', function () { /* ... */ });\n\n$router-\u003edispatch();\n```\n\nIf you don't care about HTTP verbs, you can use the `any()` method.\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\n\n$router = Router::create();\n\n$router-\u003eany('/', function () {\n    return 'This is Home! No matter what the HTTP method is!';\n});\n\n$router-\u003edispatch();\n```\n\n### Controllers\n\n#### Closure Controllers\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\n\n$router = Router::create();\n\n$router-\u003eget('/', function () {\n    return 'This is a closure controller!';\n});\n\n$router-\u003edispatch();\n```\n\n#### Class Method Controllers\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\n\nclass UsersController\n{\n    function index()\n    {\n        return 'Class: UsersController \u0026 Method: index';\n    }\n\n    function handle()\n    {\n        return 'Class UsersController.';\n    }\n}\n\n$router = Router::create();\n\n// Controller: Class=UsersController Method=index()\n$router-\u003eget('/method', [UsersController::class, 'index']);\n\n// Controller: Class=UsersController Method=handle()\n$router-\u003eget('/class', UsersController::class);\n\n$router-\u003edispatch();\n```\n\n### Route Parameters\n\nA URL might have one or more variable parts like product IDs on a shopping website.\nWe call it a route parameter.\nYou can catch them by controller method arguments like the example below.\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\n\n$router = Router::create();\n\n// Required parameter\n$router-\u003eget('/post/{id}', function ($id) {\n    return \"The content of post $id\";\n});\n\n// Optional parameter\n$router-\u003eget('/welcome/{name?}', function ($name = null) {\n    return 'Welcome ' . ($name ?: 'Dear User');\n});\n\n// Optional parameter, Optional / (Slash)!\n$router-\u003eget('/profile/?{user?}', function ($user = null) {\n    return ($user ?: 'Your') . ' profile';\n});\n\n// Optional parameter with default value\n$router-\u003eget('/roles/{role?}', function ($role = 'guest') {\n    return \"Your role is $role\";\n});\n\n// Multiple parameters\n$router-\u003eget('/post/{pid}/comment/{cid}', function ($pid, $cid) {\n    return \"The comment $cid of the post $pid\";\n});\n\n$router-\u003edispatch();\n```\n\n#### Route Parameter Patterns\n\nIn default, route parameters can have any value, but you can define regex patterns to limit them.\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\n\n$router = Router::create();\n\n// \"id\" must be numeric\n$router-\u003epattern('id', '[0-9]+');\n\n$router-\u003eget('/post/{id}', function (int $id) { /* ... */ });\n\n$router-\u003edispatch();\n```\n\n### Requests and Responses\n\nPhpRouter uses [laminas-diactoros](https://github.com/laminas/laminas-diactoros/)\n(formerly known as [zend-diactoros](https://github.com/zendframework/zend-diactoros))\npackage (v2) to provide [PSR-7](https://www.php-fig.org/psr/psr-7)\nrequest and response objects to your controllers and middleware.\n\n#### Requests\n\nYou can catch the request object in your controllers like this example:\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\nuse Laminas\\Diactoros\\ServerRequest;\nuse Laminas\\Diactoros\\Response\\JsonResponse;\n\n$router = Router::create();\n\n$router-\u003eget('/', function (ServerRequest $request) {\n    $method  = $request-\u003egetMethod();\n    $uriPath = $request-\u003egetUri()-\u003egetPath();\n    $headers = $request-\u003egetHeaders();\n    $queryParameters = $request-\u003egetQueryParams();\n    $bodyContents    = $request-\u003egetBody()-\u003egetContents();\n    // ...\n});\n\n$router-\u003edispatch();\n```\n\n#### Responses\n\nThe example below illustrates the built-in responses.\n\n```php\nuse Laminas\\Diactoros\\Response\\RedirectResponse;\nuse MiladRahimi\\PhpRouter\\Router;\nuse Laminas\\Diactoros\\Response\\EmptyResponse;\nuse Laminas\\Diactoros\\Response\\HtmlResponse;\nuse Laminas\\Diactoros\\Response\\JsonResponse;\nuse Laminas\\Diactoros\\Response\\TextResponse;\n\n$router = Router::create();\n\n$router-\u003eget('/html/1', function () {\n    return '\u003chtml\u003eThis is an HTML response\u003c/html\u003e';\n});\n$router-\u003eget('/html/2', function () {\n    return new HtmlResponse('\u003chtml\u003eThis is also an HTML response\u003c/html\u003e', 200);\n});\n$router-\u003eget('/json', function () {\n    return new JsonResponse(['error' =\u003e 'Unauthorized!'], 401);\n});\n$router-\u003eget('/text', function () {\n    return new TextResponse('This is a plain text...');\n});\n$router-\u003eget('/empty', function () {\n    return new EmptyResponse(204);\n});\n$router-\u003eget('/redirect', function () {\n    return new RedirectResponse('https://miladrahimi.com');\n});\n\n$router-\u003edispatch();\n```\n\n### Views\n\nYou might need to create a classic-style server-side rendered (SSR) website that uses views.\nPhpRouter has a simple feature for working with PHP/HTML views.\nLook at the following example.\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\nuse MiladRahimi\\PhpRouter\\View\\View\n\n$router = Router::create();\n\n// Setup view feature and set the directory of view files\n$router-\u003esetupView(__DIR__ . '/../views');\n\n$router-\u003eget('/profile', function (View $view) {\n    // It looks for a view with path: __DIR__/../views/profile.phtml\n    return $view-\u003emake('profile', ['user' =\u003e 'Jack']);\n});\n\n$router-\u003eget('/blog/post', function (View $view) {\n    // It looks for a view with path: __DIR__/../views/blog/post.phtml\n    return $view-\u003emake('blog.post', ['post' =\u003e $post]);\n});\n\n$router-\u003edispatch();\n```\n\nThere is also some points:\n* View files must have the \".phtml\" extension (e.g. `profile.phtml`).\n* You can separate directories with `.` (e.g. `blog.post` for `blog/post.phtml`).\n\nView files are pure PHP or mixed with HTML.\nYou should use PHP language with template style in the view files.\nThis is a sample view file:\n\n```php\n\u003ch1\u003e\u003c?php echo $title ?\u003e\u003c/h1\u003e\n\u003cul\u003e\n    \u003c?php foreach ($posts as $post): ?\u003e\n        \u003cli\u003e\u003c?php echo $post['content'] ?\u003e\u003c/li\u003e\n    \u003c?php endforeach ?\u003e\n\u003c/ul\u003e\n```\n\n### Route Groups\n\nYou can categorize routes into groups.\nThe groups can have common attributes like middleware, domain, or prefix.\nThe following example shows how to group routes:\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\n\n$router = Router::create();\n\n// A group with uri prefix\n$router-\u003egroup(['prefix' =\u003e '/admin'], function (Router $router) {\n    // URI: /admin/setting\n    $router-\u003eget('/setting', function () {\n        return 'Setting Panel';\n    });\n});\n\n// All of group attributes together!\n$attributes = [\n    'prefix' =\u003e '/admin',\n    'domain' =\u003e 'shop.example.com',\n    'middleware' =\u003e [AuthMiddleware::class],\n];\n\n$router-\u003egroup($attributes, function (Router $router) {\n    // URL: http://shop.example.com/admin/users\n    // Domain: shop.example.com\n    // Middleware: AuthMiddleware\n    $router-\u003eget('/users', [UsersController::class, 'index']);\n});\n\n$router-\u003edispatch();\n```\n\nThe group attributes will be explained later in this documentation.\n\nYou can use [Attributes](src/Routing/Attributes.php) enum, as well.\n\n### Middleware\n\nPhpRouter supports middleware.\nYou can use it for different purposes, such as authentication, authorization, throttles, and so forth.\nMiddleware runs before and after controllers, and it can check and manipulate requests and responses.\n\nHere you can see the request lifecycle considering some middleware:\n\n```\n[Request]  ↦ Router ↦ Middleware 1 ↦ ... ↦ Middleware N ↦ Controller\n                                                              ↧\n[Response] ↤ Router ↤ Middleware 1 ↤ ... ↤ Middleware N ↤ [Response]\n```\n\nTo declare a middleware, you can use closures and classes just like controllers.\nTo use the middleware, you must group the routes and mention the middleware in the group attributes.\nCaution! The middleware attribute in groups takes an array of middleware, not a single one.\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Laminas\\Diactoros\\Response\\JsonResponse;\n\nclass AuthMiddleware\n{\n    public function handle(ServerRequestInterface $request, Closure $next)\n    {\n        if ($request-\u003egetHeader('Authorization')) {            \n            // Call the next middleware/controller\n            return $next($request);\n        }\n\n        return new JsonResponse(['error' =\u003e 'Unauthorized!'], 401);\n    }\n}\n\n$router = Router::create();\n\n// The middleware attribute takes an array of middleware, not a single one!\n$router-\u003egroup(['middleware' =\u003e [AuthMiddleware::class]], function(Router $router) {\n    $router-\u003eget('/admin', function () {\n        return 'Admin API';\n    });\n});\n\n$router-\u003edispatch();\n```\n\nAs you can see, the middleware catches the request and the `$next` closure.\nThe closure calls the next middleware or the controller if no middleware is left.\nThe middleware must return a response, as well.\nA middleware can break the lifecycle and return a response itself,\nor it can call the `$next` closure to continue the lifecycle.\n\n### Domains and Subdomains\n\nYour application may serve different services on different domains or subdomains.\nIn this case, you can specify the domain or subdomain for your routes.\nSee this example:\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\n\n$router = Router::create();\n\n// Domain\n$router-\u003egroup(['domain' =\u003e 'shop.com'], function(Router $router) {\n    $router-\u003eget('/', function () {\n        return 'This is shop.com';\n    });\n});\n\n// Subdomain\n$router-\u003egroup(['domain' =\u003e 'admin.shop.com'], function(Router $router) {\n    $router-\u003eget('/', function () {\n        return 'This is admin.shop.com';\n    });\n});\n\n// Subdomain with regex pattern\n$router-\u003egroup(['domain' =\u003e '(.*).example.com'], function(Router $router) {\n    $router-\u003eget('/', function () {\n        return 'This is a subdomain';\n    });\n});\n\n$router-\u003edispatch();\n```\n\n### Route Names\n\nYou can assign names to your routes and use them in your codes instead of the hard-coded URLs.\nSee this example:\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\nuse Laminas\\Diactoros\\Response\\JsonResponse;\nuse MiladRahimi\\PhpRouter\\Url;\n\n$router = Router::create();\n\n$router-\u003eget('/about', [AboutController::class, 'show'], 'about');\n$router-\u003eget('/post/{id}', [PostController::class, 'show'], 'post');\n$router-\u003eget('/links', function (Url $url) {\n    return new JsonResponse([\n        'about' =\u003e $url-\u003emake('about'),             /* Result: /about  */\n        'post1' =\u003e $url-\u003emake('post', ['id' =\u003e 1]), /* Result: /post/1 */\n        'post2' =\u003e $url-\u003emake('post', ['id' =\u003e 2])  /* Result: /post/2 */\n    ]);\n});\n\n$router-\u003edispatch();\n```\n\n### Current Route\n\nYou might need to get information about the current route in your controller or middleware.\nThis example shows how to get this information.\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\nuse Laminas\\Diactoros\\Response\\JsonResponse;\nuse MiladRahimi\\PhpRouter\\Routing\\Route;\n\n$router = Router::create();\n\n$router-\u003eget('/{id}', function (Route $route) {\n    return new JsonResponse([\n        'uri'    =\u003e $route-\u003egetUri(),            /* Result: \"/1\" */\n        'name'   =\u003e $route-\u003egetName(),           /* Result: \"sample\" */\n        'path'   =\u003e $route-\u003egetPath(),           /* Result: \"/{id}\" */\n        'method' =\u003e $route-\u003egetMethod(),         /* Result: \"GET\" */\n        'domain' =\u003e $route-\u003egetDomain(),         /* Result: null */\n        'parameters' =\u003e $route-\u003egetParameters(), /* Result: {\"id\": \"1\"} */\n        'middleware' =\u003e $route-\u003egetMiddleware(), /* Result: []  */\n        'controller' =\u003e $route-\u003egetController(), /* Result: {}  */\n    ]);\n}, 'sample');\n\n$router-\u003edispatch();\n```\n\n### IoC Container\n\nPhpRouter uses [PhpContainer](https://github.com/miladrahimi/phpcontainer) to provide an IoC container for the package itself and your application's dependencies.\n\n#### How does PhpRouter use the container?\n\nPhpRouter binds route parameters, HTTP Request, Route (Current route), Url (URL generator), Container itself.\nThe controller method or constructor can resolve these dependencies and catch them.\n\n#### How can your app use the container?\n\nJust look at the following example.\n\n```php\nuse MiladRahimi\\PhpContainer\\Container;\nuse MiladRahimi\\PhpRouter\\Router;\n\n$router = Router::create();\n\n$router-\u003egetContainer()-\u003esingleton(Database::class, MySQL::class);\n$router-\u003egetContainer()-\u003esingleton(Config::class, JsonConfig::class);\n\n// Resolve directly\n$router-\u003eget('/', function (Database $database, Config $config) {\n    // Use MySQL and JsonConfig...\n});\n\n// Resolve container\n$router-\u003eget('/', function (Container $container) {\n    $database = $container-\u003eget(Database::class);\n    $config = $container-\u003eget(Config::class);\n});\n\n$router-\u003edispatch();\n```\n\nCheck [PhpContainer](https://github.com/miladrahimi/phpcontainer) for more information about this powerful IoC container.\n\n### Error Handling\n\nYour application runs through the `Router::dispatch()` method.\nYou should put it in a `try` block and catch exceptions.\nIt throws your application and PhpRouter exceptions.\n\n```php\nuse MiladRahimi\\PhpRouter\\Router;\nuse MiladRahimi\\PhpRouter\\Exceptions\\RouteNotFoundException;\nuse Laminas\\Diactoros\\Response\\HtmlResponse;\n\n$router = Router::create();\n\n$router-\u003eget('/', function () {\n    return 'Home.';\n});\n\ntry {\n    $router-\u003edispatch();\n} catch (RouteNotFoundException $e) {\n    // It's 404!\n    $router-\u003egetPublisher()-\u003epublish(new HtmlResponse('Not found.', 404));\n} catch (Throwable $e) {\n    // Log and report...\n    $router-\u003egetPublisher()-\u003epublish(new HtmlResponse('Internal error.', 500));\n}\n```\n\nPhpRouter throws the following exceptions:\n\n* `RouteNotFoundException` if PhpRouter cannot find any route that matches the user request.\n* `InvalidCallableException` if PhpRouter cannot invoke the controller or middleware.\n\nThe `RouteNotFoundException` should be considered `404 Not found` error.\n\n## License\n\nPhpRouter is initially created by [Milad Rahimi](https://miladrahimi.com) and released under the [MIT License](http://opensource.org/licenses/mit-license.php).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiladrahimi%2Fphprouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmiladrahimi%2Fphprouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiladrahimi%2Fphprouter/lists"}