Resonance: A New Async PHP Framework
Tags: php, webdev, programming, opensource
Published: 2023-10-24 23:28:25

## New PHP Framework

I spent the last year working on the new PHP framework to push this programming language further into the modern era.

I firmly believe that the future of PHP lies in [Fibers](https://www.php.net/manual/en/language.fibers.php), Coroutines, and libraries like [Swoole](https://www.swoole.com/). 

## The Bright Future of PHP

Most people know PHP just as a website framework, but it's much more - it can serve as a communication hub in your infrastructure that interconnects all your services through REST API, GraphQL, WebSockets, gRPC, and more. 

It's effortless to prototype and write new features in PHP. PHP is also straightforward to extend; if necessary, replacing parts of your application with code written in a different language is simple. It's the perfect starting point when creating new applications.

## About Resonance 

Resonance is centered around this idea - to quickly start from the ground up in the asynchronous environment and be able to set up all the necessary services and APIs and then swap, replace, or expand all the application's components. 

### Attributes First

Everything is as modular as possible, with only minimal central configuration files - everything is configured through Attributes. For example:

```php
<?php

namespace App\HttpResponder;

use App\DatabaseEntity\BlogPostForDisplay;
use App\HttpRouteSymbol;
use Distantmagic\Resonance\Attribute\RespondsToHttp;
use Distantmagic\Resonance\Attribute\RouteParameter;
use Distantmagic\Resonance\Attribute\Singleton;
use Distantmagic\Resonance\HttpInterceptableInterface;
use Distantmagic\Resonance\HttpResponder;
use Distantmagic\Resonance\HttpResponder\HttpController;
use Distantmagic\Resonance\RequestMethod;
use Distantmagic\Resonance\SingletonCollection;
use Distantmagic\Resonance\TwigTemplate;

#[RespondsToHttp(
    method: RequestMethod::GET,
    pattern: '/blog/{blog_post_slug}',
    routeSymbol: HttpRouteSymbol::BlogPostShow,
)]
#[Singleton(collection: SingletonCollection::HttpResponder)]
final readonly class BlogPostShow extends HttpController
{
    public function handle(
        #[RouteParameter(from: 'blog_post_slug')]
        BlogPostForDisplay $blogPost,
    ): HttpInterceptableInterface {
        return new TwigTemplate('turbo/website/blog_post.twig', [
            'blog_post' => $blogPost,
        ]);
    }
}
```

### Asynchronous GraphQL in PHP

You can build the entire GraphQL schema in PHP using attributes:

```php
<?php

use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use Distantmagic\Resonance\Framework\Attribute\Singleton;
use Distantmagic\Resonance\Framework\SwooleFuture;

#[Singleton]
final class PingType extends ObjectType
{
    public function __construct()
    {
        parent::__construct([
            'name' => 'Ping',
            'description' => 'Test field',
            'fields' => [
                'message' => [
                    'type' => Type::string(),
                    'description' => 'Always responds with pong',
                    'resolve' => $this->resolveMessage(...),
                ],
            ],
        ]);
    }

    private function resolveMessage(): SwooleFuture
    {
        return new SwooleFuture(function () {
            sleep(1);

            return 'pong';
        });
    }
}
```

This query is going to take 1 second (instead of 3), since the field is resolved asynchronously:

```graphql
query MultiPing() {
    ping1: ping { message }
    ping2: ping { message }
    ping3: ping { message }
}
```

### Promise-like Objects in PHP

Swoole's coroutines are wrapped inside a SwooleFuture object, which provides easy access to asynchronous features:

```php
<?php

use Distantmagic\Resonance\SwooleFuture;

$future1 = new SwooleFuture(function (int $value) {
    assert($value === 1);

    return $value + 2;
});

$future2 = $future1->then(new SwooleFuture(function (int $value) {
    assert($value === 3);

    return $value + 4;
}));

assert($future2->resolve(1)->result === 7);
```

### Much more

The project is free and open source. 

You can check the documentation here: https://resonance.distantmagic.com/docs/features/
GitHub repo: https://github.com/distantmagic/resonance

Feel free to join the community: https://resonance.distantmagic.com/community/

Resonance is new, and it's my first open-source project of this magnitude. Currently, I am working on it full-time. If you try it out and Resonance will help you with your projects, I'd be the happiest man alive.

If you find the project interesting please leave me a star on GitHub!