Search by

Cohesive PHP 8.4+ framework: attribute routing, immutable HTTP, typed config, and security middleware out of the box.

Package info

github.com/ophelios-studio/zephyrus-core

pkg:composer/zephyrus-framework/core

Statistics

Installs: 248

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 3

v0.16.0 2026-11-14 03:01 UTC

This package is auto-updated.

Last update: 2026-11-15 21:01:18 UTC


README

Zephyrus

CI codecov Packagist PHP PHPStan License: MIT

A cohesive PHP 8.4+ framework core for server-rendered applications and JSON APIs. Attribute-based routing, immutable HTTP objects, typed configuration, and a full security middleware stack that refuses to boot when a declared protection is not mounted. It is a library, not a skeleton generator: your application is your own classes, a config.yml and a front controller.

Documentation  ·  Documentation en français  ·  Changelog

Highlights

  • Routes live next to their controller. #[Get], #[Post] and the other verb attributes sit on the method that answers, #[Root] prefixes a class, controllers are discovered from a directory, and placeholders are cast to the declared parameter type. Routing
  • Security is wired, and checked. Each security: setting (HTTPS, allowed hosts, CSRF, body size, headers) must be enforced by a mounted middleware built from it, or acknowledged as enforced elsewhere: otherwise build() refuses to boot and names the middleware to mount. Security
  • Configuration refuses mistakes. config.yml is read into typed sections, a misspelled key stops the boot with a suggestion, and !env reads values from the environment. Configuration
  • Requests and responses are immutable. Request and Response are readonly values: withHeader() returns a new response instead of changing the one you hold. HTTP
  • Sessions and CSRF protection. Session middleware, flash messages, a CSRF middleware that requires a synchronizer token on every state-changing request, and an optional PostgreSQL session store. Sessions
  • A PostgreSQL layer on explicit SQL. Parameterised queries, transactions, brokers and entities, and paginated, sorted and filtered listings from request input. It is not an ORM. Data access

Also in the package: Latte views, validation, localization, mail, uploads and cryptography.

Installation

composer require zephyrus-framework/core

Before 1.0 a minor version may break the API: read the changelog before moving to the next one.

Requirement Version
PHP ^8.4
Extensions mbstring, pdo, fileinfo, intl, sodium
Database pdo_pgsql, for a database: section (PostgreSQL)
Optional apcu, to cache locale catalogs with CachedLocaleLoader

Runtime dependencies: symfony/yaml, vlucas/phpdotenv, latte/latte, tracy/tracy, phpmailer/phpmailer.

A first application

Three files boot an application, once composer.json maps the App\ namespace to app/ ("autoload": { "psr-4": { "App\\": "app/" } }, then composer dump-autoload).

config.yml:

application:
  environment: !env APP_ENV, production
  debug: !env APP_DEBUG, false

app/Controllers/HelloController.php:

<?php

declare(strict_types=1);

namespace App\Controllers;

use Zephyrus\Controller\Controller;
use Zephyrus\Http\Response;
use Zephyrus\Routing\Attribute\Get;

final class HelloController extends Controller
{
    #[Get('/hello')]
    public function hello(): Response
    {
        return $this->json(['message' => 'Hello, world.']);
    }
}

public/index.php, the front controller:

<?php

declare(strict_types=1);

use Zephyrus\Core\ApplicationBuilder;
use Zephyrus\Core\Config\Configuration;
use Zephyrus\Http\Request;
use Zephyrus\Routing\Router;

$root = dirname(__DIR__);
require $root . '/vendor/autoload.php';

$config = Configuration::fromYamlFile($root . '/config.yml');
$router = (new Router())->discoverControllers('App\\Controllers', $root . '/app/Controllers');

ApplicationBuilder::create()
    ->withConfiguration($config, basePath: $root)
    ->withRouter($router)
    ->build()
    ->handle(Request::fromGlobals())
    ->send();

PHP's built-in server is enough for development. The configuration defaults to production, so set APP_ENV=dev on your machine:

APP_ENV=dev php -S 127.0.0.1:8000 -t public
curl -i http://127.0.0.1:8000/hello
HTTP/1.1 200 OK
content-type: application/json; charset=utf-8

{"message":"Hello, world."}

The output is abridged: the real response carries more headers (Host, Date, X-Powered-By and so on).

An unknown path answers 404 Not Found, and POST /hello answers 405 Method Not Allowed with allow: GET, HEAD.

The built-in server is for development only. The first application tutorial goes on with sessions, CSRF protection, validation, Latte views and a test.

Development

git clone https://github.com/ophelios-studio/zephyrus-core zephyrus-core
cd zephyrus-core
composer install
composer test      # PHPUnit
composer analyse   # PHPStan level 8 on src/

The PostgreSQL integration tests are skipped unless ZEPHYRUS_TEST_PGSQL_DSN holds a PDO DSN with its credentials; CI always runs them. To run them against a throwaway container:

docker run --rm -d --name zephyrus-pgsql -e POSTGRES_PASSWORD=postgres -p 55432:5432 postgres:16
until docker exec zephyrus-pgsql pg_isready -h 127.0.0.1 -U postgres; do sleep 1; done
ZEPHYRUS_TEST_PGSQL_DSN='pgsql:host=127.0.0.1;port=55432;dbname=postgres;user=postgres;password=postgres' composer test
docker stop zephyrus-pgsql

Run with coverage (requires Xdebug): XDEBUG_MODE=coverage php vendor/bin/phpunit --coverage-text.

A pull request to dev must pass the CI checks (commit messages, and the PHP matrix running the dependency audit, the static analysis and the tests) and codecov/patch before it can merge. Codecov requires 90% coverage on each patch, and the project may not drop more than 0.5%. Every change should come with tests.

Commits are one semantic line (type(scope): description), with no body and no co-author trailer. The pull request title is checked the same way, because GitHub squash-merges with it. Check both before pushing:

.github/scripts/check-commit-messages.sh origin/dev..HEAD
.github/scripts/check-commit-messages.sh --title "feat(scope): description"

License

MIT, see LICENSE.