Hi folks!!! I always ear php haters talk about a language I do not know. They do not know the language they are talking about. And to show them a little example of what php8 is able to do, I've create a simple exercice: a php router with php attributes.
Create public
folder. I mean, .. a folder called "public". Then create an index.php
file inside. And follow the steps in this article.
The attribute
First of all, ... you can create a php class Route. the attributes is simple the #[Attribute]
. Attribute syntax starts from #[
and finisci with ]
. You can "mark" a class, a method, a property, .... with attributes.
#[Attribute]
class Route
{
public function __construct(
private string $method = 'GET',
private string $path = '/',
) { }
}
A Response class
This is useless for the purpose of this post, but I've made a little video (in italian). And I've just copied and pasted the code here. This object aims to decorate the json for a generic response, with some links. It make easy website navigation at the end of the post.
class Response
{
public function __construct(private array $json = []) { }
public function getContent()
{
return json_encode(
array_merge(
$this->json,
[
'@link' => [
'http://localhost:8888/',
'http://localhost:8888/info',
'http://localhost:8888/conclusions',
]
]
)
);
}
}
Handler interface
In some framework we call them controllers. Here I just named them Handler. The point is that each route will call its own handler.
interface Handler {
public function handle(): Response;
}
The concrete handlers
Now you can create some handlers, and att an attribute to them. Note that someone known annotations. Annotations was just a DocBlock comment. PHP attributes are structured and readable by the interpreter. You can obtain a class attribute using reflection.
#[Route('GET', '/')]
class HomeContoller implements Handler
{
public function handle(): Response
{
return new Response([
'page' => 'home'
]);
}
}
#[Route('GET', '/info')]
class InfoController implements Handler
{
public function handle(): Response
{
return new Response([
'page' => 'info'
]);
}
}
Configuration
I've also made a little configuration file: a list of handler, .. controller, .. call them as you like. Doesnt matter.
$routes = [
HomeContoller::class,
InfoController::class,
];
Reading attributes
Here I've create a function. The function read an array of handlers/controllers. For each handlers/controllers get a reflection instance, get attributes from the instance. Attributes (Route) indicate the http method and the path. If the route corresponds to the handler one, then handle the handler.
function router(array $routes): Response {
foreach($routes as $handler) {
$reflection = new ReflectionClass($handler);
$attributes = $reflection->getAttributes(Route::class);
foreach($attributes as $attribute) {
if ($attribute->getArguments()[0] === $_SERVER['REQUEST_METHOD']) {
if ($attribute->getArguments()[1] === $_SERVER['REQUEST_URI']) {
return (new $handler)->handle();
}
}
}
}
}
$response = router($routes);
echo $response->getContent();
Run built-in serve
Now You have your amazing router. You can try it. Just run
php -S localhost:8888 -t public
And see it working.
Conclusions
The conclusion is that php is amazing. A lot of people do not know it. all of them know php3, maybe. Once I heard someone say: "wow, .. php have also classes". So, .. LOL.
Well, .. add a new controller:
#[Route('GET', '/conclusions')]
class ConclusionsController implements Handler
{
public function handle(): Response
{
return new Response([
'message' => 'If you like this post, ... leave a like',
'and' => 'and follow me for more post like this',
]);
}
}
Then update also the configuration:
$routes = [
HomeContoller::class,
InfoController::class,
ConclusionsController::class,
];
And if you speak italian you can see my video on youtub
Top comments (4)
Did you have a github repository with this sample?
Yes!! You can see the code here. Is not on packagist. I've made it at exercice to start to show the way I like to apply tests in a legacy code. Actually the code you can see could be quite different because even if the related video is scheduled, .. the generated code is visible on github right now. In next videos I want also to show how to do a pull request and/or make issues. Feel free to contribute, .. or not ^_^
Great article! Thank for pushing PHP forward!
Have you seen my automatic dependency injection's article?