Bref helps you build serverless PHP applications.
Bref brings support for PHP on serverless providers (AWS Lambda only for now) but also goes beyond that: it provides a deployment process tailored for PHP as well as the ability to create:
- classic lambdas (a function taking an "event" and returning a result)
- HTTP applications written with popular PHP frameworks
- CLI applications
It is currently in beta version and will get more and more complete with time, but it is used in production successfully. Contributions are welcome!
If you want to understand what serverless is please read the Serverless and PHP: introducing Bref article.
Use case examples:
- APIs
- workers
- crons/batch processes
- GitHub webhooks
- Slack bots
Interested about performances? Head over here for a benchmark.
For now Bref only works with AWS Lambda. Help to support other providers is welcome.
For deploying, Bref internally uses the serverless framework. At first you should not have to deal with the serverless framework itself but you need to install it.
- Create an AWS account if you don't already have one
- Install the serverless framework:
npm install -g serverless
- Setup your AWS credentials: create an AWS access key and either configure it using an environment variable (easy solution) or setup
aws-cli
(and runaws configure
)
Bref will then use AWS credentials and the serverless framework to deploy your application.
To create your first lambda application create an empty directory and run the following commands:
composer require mnapoli/bref
vendor/bin/bref init
The init
command will create the required files, including a bref.php
file which will be your application:
<?php
require __DIR__.'/vendor/autoload.php';
λ(function (array $event) {
return [
'hello' => $event['name'] ?? 'world',
];
});
Note that the λ
function is just a simple function (with a funny name) that boots Bref and runs it, here is the equivalent code without that shortcut function:
$app = new \Bref\Application;
$app->simpleHandler(function (array $event) {
return [
'hello' => $event['name'] ?? 'world',
];
});
$app->run();
For now our lambda is a simple lambda that can be invoked manually. Creating HTTP applications is covered below in the documentation.
Let's deploy our application:
vendor/bin/bref deploy
On the first deploy Bref will create the lambda and every other resource needed. If you redeploy later your existing lambda will be updated.
You can trigger your lambda manually using the CLI:
vendor/bin/bref invoke
Or using the AWS PHP SDK from another PHP application:
$lambda = new \Aws\Lambda\LambdaClient([
'version' => 'latest',
'region' => 'us-east-1',
]);
$result = $lambda->invoke([
'FunctionName' => '<function-name>',
'InvocationType' => 'RequestResponse',
'LogType' => 'None',
'Payload' => json_encode([ /* your event data */ ]),
]);
$payload = json_decode($result->get('Payload')->getContents(), true);
Bref provides a helper to invoke the lambda locally, on your machine instead of the serverless provider:
php bref.php bref:invoke
# If you want to pass event data:
php bref.php bref:invoke --event='{"name":"foo"}'
Bref provides bridges to use your HTTP framework to write a HTTP applications. By default Bref supports any PSR-15 compliant framework, as well as Symfony and Laravel (read below).
Here is an example using the Slim framework to handle requests (native PSR-15 support for Slim is in the works):
<?php
use Bref\Bridge\Slim\SlimAdapter;
require __DIR__.'/vendor/autoload.php';
$slim = new Slim\App;
$slim->get('/dev', function ($request, $response) {
$response->getBody()->write('Hello world!');
return $response;
});
$app = new \Bref\Application;
$app->httpHandler(new SlimAdapter($slim));
$app->run();
If you don't need a framework, here is a simple example:
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Zend\Diactoros\Response\JsonResponse;
// ...
$app = new \Bref\Application;
$app->httpHandler(new class implements RequestHandlerInterface {
public function handle(ServerRequestInterface $request): ResponseInterface
{
return new JsonResponse('Hello world');
}
});
$app->run();
The $app->httpHandler()
method lets us define the handler for HTTP requests.
When your lambda is deployed, a URL will be created so that your application is accessible online. The URL can be retrieved using vendor/bin/bref info
. Calling the URL will trigger your lambda and Bref will run your "http handler". For example using curl:
curl https://xxxxx.execute-api.xxxxx.amazonaws.com/dev/
Bref provides a helper to preview the application locally. It works with PHP's built-in webserver:
php -S 127.0.0.1:8000 bref.php
The application is then available at http://localhost:8000.
Since Bref works with PSR-15 you are not even required to use a PHP framework. You could write your own "HTTP handler" by providing an implementation of Psr\Http\Server\RequestHandlerInterface
to $app->httpHandler()
.
Read the documentation for deploying Symfony applications.
Read the documentation for deploying Laravel applications.
See this StackOverflow question for a more detailed answer. The short version is AWS requires a prefix containing the stage name (dev/prod/…).
If you use a custom domain for your application this prefix will disappear. If you don't, you need to write routes with this prefix in your framework.
Bref provides an abstraction to easily run CLI commands in lambdas. You can define a CLI application using Symfony Console or Silly (which extends and simplifies Symfony Console). Once the lambda is deployed you can then "invoke" the CLI commands in the lambda using bref cli -- <command>
.
<?php
require __DIR__.'/vendor/autoload.php';
$silly = new \Silly\Application;
$silly->command('hello [name]', function (string $name = 'World!', $output) {
$output->writeln('Hello ' . $name);
});
$app = new \Bref\Application;
$app->cliHandler($silly);
$app->run();
To run CLI commands in the lambda, run bref cli
on your computer:
$ vendor/bin/bref cli
[…]
# Runs the CLI application without arguments and displays the help
$ vendor/bin/bref cli -- hello
Hello World!
$ vendor/bin/bref cli -- hello Bob
Hello Bob
As you can see, all arguments and options after bref cli --
are forwarded to the CLI command running on lambda.
To test your CLI commands locally (on your machine), run:
php bref.php <commands and options>
Bref automatically registers a special bref:invoke
command to your CLI application. That command lets you invoke on your machine a simpleHandler
you may have defined:
php bref.php bref:invoke
As you may have noted, Bref lets you define 3 kinds of handlers:
$app->simpleHandler(function () {
return 'Hello';
});
$app->httpHandler($httpFramework);
$app->cliHandler($console);
$app->run();
If you want to, you can define those 3 handlers in the same application. On execution Bref recognizes if the application is invoked through HTTP, through bref cli
(for CLI commands) or simply through a standard invocation. It will then execute the appropriate handler.
The filesystem on lambdas is read-only (except for the /tmp
folder). You should not try to write application logs to disk.
The easiest solution is to push logs to AWS Cloudwatch (Amazon's solution for logs). Bref (and AWS Lambda) will send to Cloudwatch anything you write on stdout
(using echo
for example) or stderr
. If you are using Monolog this means you will need to configure Monolog to write to the output (contribution welcome: clarify with an example).
If you have more specific needs you can of course push logs to anything, for example Logstash, Papertrail, Loggly, etc.
You can read the AWS Cloudwatch logs in the AWS console or via the CLI:
vendor/bin/bref logs
If you want to tail the logs:
vendor/bin/bref logs --tail
To deploy the application, run:
vendor/bin/bref deploy
A stage can be provided to deploy to multiple stages, for example staging, production, etc:
vendor/bin/bref deploy --stage=prod
When deploying Composer dependencies will be installed and optimized for production (composer install --no-dev --no-scripts --classmap-authoritative
).
You can execute additional scripts by using a build hook. Those can be defined in a .bref.yml
file:
hooks:
build:
- 'npm install'
If you need a specific PHP version, you can define it in a .bref.yml
file:
php:
version: 7.2.5
Here is the list of versions available:
- 7.2.5
You can also define php.ini
configuration flags (full list here) and activate extensions:
php:
configuration:
memory_limit: 256M
extensions:
- redis
Here is the list of extensions available:
- Intl:
intl
(be aware that this extension adds about 25mb to your lambda) - MongoDB:
mongodb
- New Relic:
newrelic
- Redis:
redis
You can delete your lambda on the hosting provider by running:
vendor/bin/bref remove
There are a lot of detailed TODO
notes in the codebase. Feel free to work on these.
Here are projects using Bref, feel free to add yours in a pull request: