I made a php router with attributes
Tags: php, attributes, php8
Published: 2023-04-23 09:58:27

---
title: I made a php router with attributes
published: true
description: I'll make a little example of usage of attributes in php
tags: php, attributes, php8
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g5hhq81ryrbbav5bfwqi.jpg
series: php
---

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.

```php
 #[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.

```php
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.

```php
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.

```php
#[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.

```php
$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.

```php
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:

```php
#[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:

```php
$routes = [
    HomeContoller::class,
    InfoController::class,
    ConclusionsController::class,
];
```

And if you speak italian you can see [my video on youtub](https://youtu.be/zwcSVjM9Iiw)