Simple PHP HTTP & CLI application base using:
- PSR-7 HTTP Message / PSR-17 HTTP Factories: nyholm/psr7
- PSR-15 HTTP Handlers / Middleware: northwoods/broker
- PSR-11: Container: php-di/php-di
- Routing: nikic/fast-route
- Console: symfony/console
- Basing on standardized interfaces and well tested components;
- Not being tied to any specific framework;
- Being able to make lightweight and customizable apps fast with just PHP's
includes and anonymous functions.
$app = new Flow\Application;Register services (using: php-di/php-di):
$services = [];
$services['hello'] = fn() => new class {
public function sayHello($name) { return "Hello {$name}!"; }
};
$app->getContainerBuilder()->addDefinitions($services);Register routes (using: nikic/fast-route):
$app->getRouteCollector()->get('/hello[/{name}]', function($request, $name = 'World') use ($app) {
$container = $app->getContainer();
$response = $container->get('http_factory')->createResponse(200);
$response->getBody()->write(
$container->get('hello')->sayHello($name)
);
return $response;
});Register middleware (using: northwoods/broker):
$app->getBroker()->append(new MyMiddleware);…or defer construction until after bootstrap when the middleware needs services from the container:
$app->getBroker()->appendDeferred(fn() => new MyMiddleware(
$app->getContainer()->get('hello'),
));Register console commands (using: symfony/console):
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
$app->getConsole()->register('hello')
->setDescription('Say hello')
->addArgument('name', null, 'Your name', 'World')
->setCode(function(InputInterface $input, OutputInterface $output) use ($app) {
$service = $app->getContainer()->get('hello');
$output->writeLn($service->sayHello($input->getArgument('name')));
return 0;
});…or use factories to lazy-load commands:
use Flow\Command\RequestCommand;
use Flow\Emitter\ConsoleEmitter;
$commands = [];
$commands['request'] = fn() => new RequestCommand(
$app->getServerRequestCreator(),
$app->getBroker(),
new ConsoleEmitter
);
$app->getCommandLoader()->addFactories($commands);At the end of the script, simply run the application:
$app->run();Try it from terminal:
$ php examples/application.php hello "Grim Reaper"
$ php examples/application.php request GET /helloRegister all middleware, routes and services before bootstrap. $app->run()
and $app->handle($request) bootstrap on their own. The router middleware is
appended last during bootstrap and terminates the pipeline on a matched route,
so anything appended afterwards is unreachable for matched routes; routes and
services registered afterwards are ignored.
To use the app without the PHP globals (tests, workers), dispatch PSR-7
requests directly; call bootstrap() first if you need services before the
first request:
$app->bootstrap();
$app->getContainer()->get('hello');
$response = $app->handle($app->getHttpFactory()->createServerRequest('GET', '/hello'));$ composer test # phpunit
$ composer analyse # phpstanMIT