Bref Lambda Reference
Complete guide for deploying PHP applications on AWS Lambda using the Bref framework.
Table of Contents
- Project Setup
- Handler Implementation
- Symfony Integration
- Cold Start Optimization
- Configuration
- Deployment
Project Setup
Composer Configuration
{
"name": "my/symfony-lambda",
"description": "Symfony on AWS Lambda",
"require": {
"php": "^8.2",
"bref/bref": "^2.0",
"bref/symfony-bridge": "^1.0",
"symfony/framework-bundle": "^6.0",
"symfony/yaml": "^6.0",
"symfony/dotenv": "^6.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"allow-plugins": {
"php-http/discovery": true
}
}
}
Serverless Configuration
# serverless.yml
service: symfony-lambda
provider:
name: aws
runtime: php-82
memorySize: 512
timeout: 20
region: us-east-1
plugins:
- ./vendor/bref/bref
functions:
api:
handler: public/index.php
description: Symfony Lambda
events:
- httpApi: '*'
package:
exclude:
- node_modules/**
- .git/**
- tests/**
Handler Implementation
Basic Lambda Handler
// public/index.php
use Bref\Bref;
use Bref\Context\Context;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
require __DIR__.'/../vendor/autoload.php';
Bref::initialize();
$app = require __DIR__.'/../config/bootstrap.php';
$handler = function ($event, Context $context) use ($app) {
$request = Request::createFromGlobals();
$response = $app->handle($request);
return [
'statusCode' => $response->getStatusCode(),
'headers' => $response->headers->all(),
'body' => $response->getContent()
];
};
return $handler;
Symfony 6.x Integration
// public/index.php
use Bref\Symfony\Bref;
use App\Kernel;
use Symfony\Component\HttpFoundation\Request;
require_once __DIR__.'/../vendor/autoload.php';
$kernel = new Kernel($_SERVER['APP_ENV'] ?? 'dev', $_SERVER['APP_DEBUG'] ?? true);
$ Bref = new Bref($kernel);
// Run the application
return $bref->getAwsHandler();
Console Commands
// bin/console
#!/usr/bin/env php
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
require_once __DIR__.'/../vendor/autoload.php';
$kernel = new Kernel($_SERVER['APP_ENV'] ?? 'dev', true);
$application = new Application($kernel);
$application->run();
# serverless.yml - console function
functions:
console:
handler: bin/console
timeout: 120
events:
- schedule: rate(1 hour)
Symfony Integration
Kernel Configuration
// src/Kernel.php
<?php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Yaml\Yaml;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
private const CONFIG_EXTS = '.{php,yaml,yml}';
public function registerBundles(): iterable
{
$contents = require $this->getProjectDir().'/config/bundles.php';
foreach ($contents as $class => $envs) {
if ($envs[$this->environment] ?? $envs['all'] ?? false) {
yield new $class();
}
}
}
public function getProjectDir(): string
{
return dirname(__DIR__);
}
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
{
$container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
$container->setParameter('container.dumper.inline_class_loader', true);
$loader->load($this->getProjectDir().'/config/services.yaml');
}
protected function configureRoutes(RoutingConfigurator $routes): void
{
$routes->import('../config/routes.yaml');
}
}
Services Configuration
# config/services.yaml
parameters:
env(DATABASE_URL): ''
env(AWS_REGION): 'us-east-1'
services:
_defaults:
autowire: true
autoconfigure: true
bind:
$region: '%env(AWS_REGION)%'
App\:
resource: '../src/'
exclude: '../src/{Entity,Repository}'
App\Service\AwsService:
arguments:
$region: '%env(AWS_REGION)%'
Routes Configuration
# config/routes.yaml
app_home:
path: /
controller: App\Controller\HomeController::index
app_api_users:
resource: '../src/Controller/UserController.php'
type: annotation
Cold Start Optimization
Disable Unused Features
# config/packages/prod/framework.yaml
framework:
validation: false
annotations: false
serializer: false
profiler: false
services:
App\Service\HeavyService: '@App\Service\LazyHeavyService'
Lazy Services
# config/services.yaml
services:
App\Service\LazyReportService:
class: App\Service\ReportService
lazy: true
Optimize Composer Autoload
{
"autoload": {
"classmap": ["src/"],
"psr-4": {
"App\\": "src/"
}
},
"config": {
"optimize-autoloader": true
}
}
Minimal Bundles
// config/bundles.php
return [
// Keep only essential bundles
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
];
Configuration
Environment Variables
# serverless.yml
provider:
environment:
APP_ENV: ${self:custom.stage}
DATABASE_URL: ${ssm:/my-app/database-url}
AWS_REGION: ${self:provider.region}
IAM Permissions
provider:
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:Query
- dynamodb:Scan
Resource: 'arn:aws:dynamodb:${self:provider.region}:*:table/users'
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
Resource: 'arn:aws:s3:::my-bucket/*'
VPC Configuration
functions:
api:
vpc:
securityGroupIds:
- !GetAtt LambdaSecurityGroup.GroupId
subnetIds:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
Deployment
Deploy Commands
# Install dependencies
composer install --no-dev --optimize-autoloader
# Deploy to dev
vendor/bin/bref deploy --stage dev
# Deploy to production
vendor/bin/bref deploy --stage prod
Stages Configuration
# serverless.yml
custom:
stage: ${opt:stage, 'dev'}
dev:
domain: dev-api.example.com
provisioned: 0
prod:
domain: api.example.com
provisioned: 5
functions:
api:
handler: public/index.php
environment:
STAGE: ${self:custom.stage}
Provisioned Concurrency
functions:
api:
handler: public/index.php
provisionedConcurrency: ${self:custom.${self:custom.stage}.provisioned}
reservedConcurrency: 10
Performance Tuning
Memory Allocation
provider:
memorySize: 1024 # More memory = more CPU
functions:
api:
memorySize: 1024
timeout: 30
PHP Configuration
provider:
environment:
PHP_INI_SCAN_DIR: /var/task/conf.d
; conf.d/lambda.ini
memory_limit = 512M
max_execution_time = 30
Testing
See testing-lambda.md for comprehensive testing patterns.
Local Development
# Start local server
composer require bref/local-server --dev
php -S localhost:8000 -t public/
Troubleshooting
Common Issues
- Cold start too slow: Disable unused Symfony features
- Memory limit exceeded: Increase memory or optimize dependencies
- Timeout errors: Increase timeout or optimize database queries
- Class not found: Run
composer dump-autoload --optimize