clue/framework-x
Framework X is a simple, fast micro framework for building reactive PHP web apps. Create routes, return PSR-7 responses, and run anywhere—behind a traditional web server or as a standalone server with ReactPHP under the hood.
composer require clue/framework-x:^0.17
index.php:
<?php
require __DIR__ . '/../vendor/autoload.php';
$app = new FrameworkX\App();
$app->get('/', fn() => React\Http\Message\Response::plaintext("Hello World!"));
$app->run();
php index.php
Access via http://localhost:8080.$app->get('/api/users/{id}', function (ServerRequestInterface $request) {
$id = $request->getAttribute('id');
return Response::json(['user_id' => $id]);
});
FrameworkX\App: Core application class.get(), post(), put(), delete(), patch(), options().middleware().Leverage async/await for non-blocking operations:
$app->middleware(function (ServerRequestInterface $request, callable $next) {
$start = microtime(true);
$response = $next($request);
$duration = microtime(true) - $start;
return $response->withHeader('X-Response-Time', $duration);
});
Automatic (Class-Based):
$app->get('/users', UserController::class); // Resolves via constructor
Explicit Container:
$container = new FrameworkX\Container([
UserService::class => fn() => new UserService($db),
]);
$app = new FrameworkX\App($container);
PHP 8.1+ auto-spawns fibers per request. For older versions, enable fiber mode:
$app = new FrameworkX\App(['fiber_mode' => true]);
Use X_LISTEN env var to override default port/host:
X_LISTEN=0.0.0.0:8080 php index.php
Customize error output via middleware:
$app->middleware(function ($request, $next) use ($app) {
try {
return $next($request);
} catch (Throwable $e) {
return Response::json(['error' => $e->getMessage()], 500);
}
});
Extend FrameworkX\App for custom integrations:
$app = new FrameworkX\App();
$app->on('start', function () {
echo "Server started!\n";
});
Fiber Mode Quirks:
fiber_mode (may cause performance overhead).await for coroutines.Route Matching:
/{param?} for optional params./users/{id?} matches /users and /users/123.Dependency Injection:
Environment Variables:
X_LISTEN overrides SERVER_NAME/PORT but does not support Unix sockets.Response Headers:
Response::json()/Response::html() will not be included. Use withHeader() before body generation.Log Requests:
$app->middleware(function ($request, $next) {
error_log($request->getUri());
return $next($request);
});
Check Fiber Context:
if (\React\Async\isRunningInFiber()) {
echo "Running in fiber!\n";
}
Validate Middleware:
$next() or return a Response. Omitting $next() breaks the chain.Test Locally:
php -S localhost:8080 public/index.php
Custom Handlers:
Override FrameworkX\Handler\RouteHandler for advanced routing logic.
Async Database:
Use React\Mysql\Connection or React\Redis with await:
$app->get('/data', async function () {
$db = new React\Mysql\Connection($config);
$result = await $db->query('SELECT * FROM users');
return Response::json($result);
});
Signal Handling:
Listen for SIGINT/SIGTERM via:
$app->on('shutdown', function () {
echo "Shutting down gracefully...\n";
});
Docker Integration:
Use the provided Dockerfile or configure X_LISTEN in docker-compose.yml:
environment:
X_LISTEN: 0.0.0.0:8080
X_ACCESS_LOG=/dev/null to skip log writes.fiber_mode: false) for CPU-bound tasks in PHP < 8.1.Response::stream() for large files to avoid memory spikes.App Constructor Options:
$app = new FrameworkX\App([
'fiber_mode' => true, // Force fiber mode (PHP < 8.1)
'access_log' => '/var/log/app.log', // Custom log path
'error_handler' => null, // Disable default error handler
]);
Middleware Order: Middleware runs top-to-bottom in registration order. Use array_unshift() for priority.
How can I help you explore Laravel packages today?