
Aws Lambda Php Integration
- 1.4k installs
- 311 repo stars
- Updated June 22, 2026
- giuseppe-trisciuoglio/developer-kit
aws-lambda-php-integration is an agent skill for provides aws lambda integration patterns for php with symfony using the bref framework. creates lambda handler classes, configures runtime layers, sets up sqs/sns event.
About
The aws-lambda-php-integration skill is designed for provides AWS Lambda integration patterns for PHP with Symfony using the Bref framework. Creates Lambda handler classes, configures runtime layers, sets up SQS/SNS event. AWS Lambda PHP Integration Patterns for deploying PHP and Symfony applications on AWS Lambda using the Bref framework. Project Structure Symfony with Bref Structure Raw PHP Structure 3. Invoke when the user deploying PHP/Symfony applications to AWS Lambda, configuring API Gateway integration, implementing serverless PHP applications, or optimizing Lambda performance with Bref.
- Bref Framework - Standard PHP on Lambda with Symfony support, built-in routing, cold start < 2s.
- Raw PHP - Minimal overhead, maximum control, cold start < 500ms.
- Creating new Lambda functions in PHP.
- Migrating existing Symfony applications to Lambda.
- Optimizing cold start performance.
Aws Lambda Php Integration by the numbers
- 1,436 all-time installs (skills.sh)
- +55 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #327 of 4,386 Backend & APIs skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
aws-lambda-php-integration capabilities & compatibility
- Capabilities
- bref framework standard php on lambda with sym · raw php minimal overhead, maximum control, col · creating new lambda functions in php · migrating existing symfony applications to lambd
What aws-lambda-php-integration says it does
Provides AWS Lambda integration patterns for PHP with Symfony using the Bref framework. Creates Lambda handler classes, configures runtime layers, sets up SQS/SNS event triggers, i
Provides AWS Lambda integration patterns for PHP with Symfony using the Bref framework. Creates Lambda handler classes, configures runtime layers, sets up SQS/S
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill aws-lambda-php-integrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.4k |
|---|---|
| repo stars | ★ 311 |
| Security audit | 3 / 3 scanners passed |
| Last updated | June 22, 2026 |
| Repository | giuseppe-trisciuoglio/developer-kit ↗ |
How do I provides aws lambda integration patterns for php with symfony using the bref framework. creates lambda handler classes, configures runtime layers, sets up sqs/sns event?
Provides AWS Lambda integration patterns for PHP with Symfony using the Bref framework. Creates Lambda handler classes, configures runtime layers, sets up SQS/SNS event.
Who is it for?
Developers using aws lambda php integration workflows documented in SKILL.md.
Skip if: Skip when the task falls outside aws-lambda-php-integration scope or needs a different stack.
When should I use this skill?
User deploying PHP/Symfony applications to AWS Lambda, configuring API Gateway integration, implementing serverless PHP applications, or optimizing Lambda performance with Bref.
What you get
Completed aws-lambda-php-integration workflow with documented commands, files, and expected deliverables.
- Lambda memory and timeout configuration
- Optimized composer.json
- Error-handling and logging checklist
By the numbers
- Recommends 512MB memory for Symfony and 256MB for raw PHP on Lambda
- Documents PHP ^8.2, bref/bref ^2.0, and Symfony ^6.0 in example composer.json
Files
AWS Lambda PHP Integration
Patterns for deploying PHP and Symfony applications on AWS Lambda using the Bref framework.
Overview
Two approaches available:
- Bref Framework - Standard PHP on Lambda with Symfony support, built-in routing, cold start < 2s
- Raw PHP - Minimal overhead, maximum control, cold start < 500ms
Both support API Gateway integration with production-ready configurations.
When to Use
- Creating new Lambda functions in PHP
- Migrating existing Symfony applications to Lambda
- Optimizing cold start performance
- Configuring API Gateway or SQS/SNS event triggers
- Setting up deployment pipelines for PHP Lambda
Instructions
1. Choose Your Approach
| Approach | Cold Start | Best For | Complexity |
|---|---|---|---|
| Bref | < 2s | Symfony apps, full-featured APIs | Medium |
| Raw PHP | < 500ms | Simple handlers, maximum control | Low |
2. Project Structure
Symfony with Bref Structure
my-symfony-lambda/
├── composer.json
├── serverless.yml
├── public/
│ └── index.php # Lambda entry point
├── src/
│ └── Kernel.php # Symfony Kernel
├── config/
│ ├── bundles.php
│ ├── routes.yaml
│ └── services.yaml
└── templates/Raw PHP Structure
my-lambda-function/
├── public/
│ └── index.php # Handler entry point
├── composer.json
├── serverless.yml
└── src/
└── Services/3. Implementation
Symfony with Bref:
// public/index.php
use Bref\Symfony\Bref;
use App\Kernel;
use Symfony\Component\HttpFoundation\Request;
require __DIR__.'/../vendor/autoload.php';
$kernel = new Kernel($_SERVER['APP_ENV'] ?? 'dev', $_SERVER['APP_DEBUG'] ?? true);
$kernel->boot();
$bref = new Bref($kernel);
return $bref->run($event, $context);Raw PHP Handler:
// public/index.php
use function Bref\Lambda\main;
main(function ($event) {
$path = $event['path'] ?? '/';
$method = $event['httpMethod'] ?? 'GET';
return [
'statusCode' => 200,
'body' => json_encode(['message' => 'Hello from PHP Lambda!'])
];
});4. Cold Start Optimization
1. Lazy loading - Defer heavy services until needed 2. Disable unused Symfony features - Turn off validation, annotations 3. Optimize composer autoload - Use classmap for production 4. Use Bref optimized runtime - Leverage PHP 8.x optimizations
5. Connection Management
// Cache AWS clients at function level
use Aws\DynamoDb\DynamoDbClient;
class DatabaseService
{
private static ?DynamoDbClient $client = null;
public static function getClient(): DynamoDbClient
{
if (self::$client === null) {
self::$client = new DynamoDbClient([
'region' => getenv('AWS_REGION'),
'version' => 'latest'
]);
}
return self::$client;
}
}Best Practices
Memory and Timeout
- Memory: Start with 512MB for Symfony, 256MB for raw PHP
- Timeout: Symfony 10-30s for cold start buffer, Raw PHP 3-10s typically sufficient
Dependencies
{
"require": {
"php": "^8.2",
"bref/bref": "^2.0",
"symfony/framework-bundle": "^6.0"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist"
}
}Error Handling
try {
$result = processRequest($event);
return [
'statusCode' => 200,
'body' => json_encode($result)
];
} catch (ValidationException $e) {
return [
'statusCode' => 400,
'body' => json_encode(['error' => $e->getMessage()])
];
} catch (Exception $e) {
error_log($e->getMessage());
return [
'statusCode' => 500,
'body' => json_encode(['error' => 'Internal error'])
];
}Logging
error_log(json_encode([
'level' => 'info',
'message' => 'Request processed',
'request_id' => $context->getAwsRequestId(),
'path' => $event['path'] ?? '/'
]));Deployment
Serverless Configuration
# serverless.yml
service: symfony-lambda-api
provider:
name: aws
runtime: php-82
memorySize: 512
timeout: 20
package:
individually: true
exclude:
- '**/node_modules/**'
- '**/.git/**'
functions:
api:
handler: public/index.php
events:
- http:
path: /{proxy+}
method: ANYDeploy and Validate
# 1. Install Bref
composer require bref/bref --dev
# 2. Test locally (validate before deploy)
sam local invoke -e event.json
# 3. Deploy
vendor/bin/bref deploy
# 4. Verify deployment
aws lambda invoke --function-name symfony-lambda-api-api \
--payload '{"path": "/", "httpMethod": "GET"}' /dev/stdoutSymfony Full Configuration
# serverless.yml for Symfony
service: symfony-lambda-api
provider:
name: aws
runtime: php-82
stage: ${self:custom.stage}
region: ${self:custom.region}
environment:
APP_ENV: ${self:custom.stage}
APP_DEBUG: ${self:custom.isLocal}
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
Resource: '*'
functions:
web:
handler: public/index.php
timeout: 30
memorySize: 1024
events:
- http:
path: /{proxy+}
method: ANY
console:
handler: bin/console
timeout: 300
events:
- schedule: rate(1 day)
plugins:
- ./vendor/bref/bref
custom:
stage: dev
region: us-east-1
isLocal: falseConstraints and Warnings
Lambda Limits
- Deployment package: 250MB unzipped maximum (50MB zipped)
- Memory: 128MB to 10GB
- Timeout: 29 seconds (API Gateway), 15 minutes for async
- Concurrent executions: 1000 default
PHP-Specific Considerations
- Cold start: PHP has moderate cold start; use Bref for optimized runtimes
- Dependencies: Keep composer.json minimal; use Lambda Layers for shared deps
- PHP version: Use PHP 8.2+ for best Lambda performance
- No local storage: Lambda containers are ephemeral; use S3/DynamoDB for persistence
Common Pitfalls
1. Large vendor folder - Exclude dev dependencies; use --no-dev 2. Session storage - Don't use local file storage; use DynamoDB 3. Long-running processes - Not suitable for Lambda; use ECS instead 4. Websockets - Use API Gateway WebSockets or AppSync instead
Security Considerations
- Never hardcode credentials; use IAM roles and SSM Parameter Store
- Validate all input data
- Use least privilege IAM policies
- Enable CloudTrail for audit logging
- Set proper CORS headers
Examples
Example 1: Create a Symfony Lambda API
Input: "Create a Symfony Lambda REST API using Bref for a todo application"
Process: 1. Initialize Symfony project with composer create-project 2. Install Bref: composer require bref/bref 3. Configure serverless.yml 4. Set up routes in config/routes.yaml 5. Test locally: sam local invoke 6. Deploy: vendor/bin/bref deploy 7. Verify: aws lambda invoke --function-name <name> --payload '{}'
Output: Complete Symfony project structure with REST API, DynamoDB integration, deployment configuration
Example 2: Optimize Cold Start for Symfony
Input: "My Symfony Lambda has 5 second cold start, how do I optimize it?"
Process: 1. Analyze services loaded at startup 2. Disable unused Symfony features (validation, annotations) 3. Use lazy loading for heavy services 4. Optimize composer autoload 5. Measure: Deploy and invoke to verify cold start < 2s
Output: Refactored Symfony configuration with cold start < 2s
Example 3: Deploy with GitHub Actions
Input: "Configure CI/CD for Symfony Lambda with Serverless Framework"
Process: 1. Create GitHub Actions workflow 2. Set up PHP environment with composer 3. Run PHPUnit tests 4. Deploy with Serverless Framework 5. Validate: Check Lambda function exists and responds
Output: Complete .github/workflows/deploy.yml with multi-stage pipeline and test automation
References
- [Bref Lambda](references/bref-lambda.md) - Complete Bref setup, Symfony integration, routing
- [Raw PHP Lambda](references/raw-php-lambda.md) - Minimal handler patterns, caching, packaging
- [Serverless Deployment](references/serverless-deployment.md) - Serverless Framework, SAM, CI/CD pipelines
- [Testing Lambda](references/testing-lambda.md) - PHPUnit, SAM Local, integration testing
AWS Lambda PHP Best Practices
Best practices, constraints, and security considerations for PHP Lambda development.
Memory and Timeout Configuration
- Memory: Start with 512MB for Symfony, 256MB for raw PHP
- Timeout: Set based on expected processing time
- Symfony: 10-30 seconds for cold start buffer
- Raw PHP: 3-10 seconds typically sufficient
Dependencies
Keep composer.json minimal:
{
"require": {
"php": "^8.2",
"bref/bref": "^2.0",
"symfony/framework-bundle": "^6.0"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist"
}
}Error Handling
Return proper Lambda responses:
try {
$result = processRequest($event);
return [
'statusCode' => 200,
'body' => json_encode($result)
];
} catch (ValidationException $e) {
return [
'statusCode' => 400,
'body' => json_encode(['error' => $e->getMessage()])
];
} catch (Exception $e) {
error_log($e->getMessage());
return [
'statusCode' => 500,
'body' => json_encode(['error' => 'Internal error'])
];
}Logging
Use structured logging:
error_log(json_encode([
'level' => 'info',
'message' => 'Request processed',
'request_id' => $context->getAwsRequestId(),
'path' => $event['path'] ?? '/'
]));Lambda Limits
- Deployment package: 250MB unzipped maximum (50MB zipped)
- Memory: 128MB to 10GB
- Timeout: 29 seconds (API Gateway), 15 minutes for async
- Concurrent executions: 1000 default
PHP-Specific Considerations
- Cold start: PHP has moderate cold start; use Bref for optimized runtimes
- Dependencies: Keep composer.json minimal; use Lambda Layers for shared deps
- PHP version: Use PHP 8.2+ for best Lambda performance
- No local storage: Lambda containers are ephemeral; use S3/DynamoDB for persistence
Common Pitfalls
1. Large vendor folder - Exclude dev dependencies; use --no-dev 2. Session storage - Don't use local file storage; use DynamoDB 3. Long-running processes - Not suitable for Lambda; use ECS instead 4. Websockets - Use API Gateway WebSockets or AppSync instead
Security Considerations
- Never hardcode credentials; use IAM roles and SSM Parameter Store
- Validate all input data
- Use least privilege IAM policies
- Enable CloudTrail for audit logging
- Set proper CORS headers
Bref Lambda Reference
Complete guide for deploying PHP applications on AWS Lambda using the Bref framework.
Table of Contents
1. Project Setup 2. Handler Implementation 3. Symfony Integration 4. Cold Start Optimization 5. Configuration 6. 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: trueOptimize 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 prodStages 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: 30PHP 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
1. Cold start too slow: Disable unused Symfony features 2. Memory limit exceeded: Increase memory or optimize dependencies 3. Timeout errors: Increase timeout or optimize database queries 4. Class not found: Run composer dump-autoload --optimize
AWS Lambda PHP Examples
Complete examples for implementing AWS Lambda with PHP and Symfony.
Example 1: Create a Symfony Lambda API
Input:
Create a Symfony Lambda REST API using Bref for a todo applicationProcess: 1. Initialize Symfony project with composer create-project 2. Install Bref: composer require bref/bref 3. Configure serverless.yml 4. Set up routes in config/routes.yaml 5. Configure deployment with vendor/bin/bref deploy
Output:
- Complete Symfony project structure
- REST API with CRUD endpoints
- DynamoDB integration
- Deployment configuration
Example 2: Optimize Cold Start for Symfony
Input:
My Symfony Lambda has 5 second cold start, how do I optimize it?Process: 1. Analyze services loaded at startup 2. Disable unused Symfony features (validation, annotations) 3. Use lazy loading for heavy services 4. Optimize composer autoload 5. Consider using raw PHP if full framework not needed
Output:
- Refactored Symfony configuration
- Optimized cold start < 2s
- Service analysis report
Example 3: Deploy with GitHub Actions
Input:
Configure CI/CD for Symfony Lambda with Serverless FrameworkProcess: 1. Create GitHub Actions workflow 2. Set up PHP environment with composer 3. Run PHPUnit tests 4. Deploy with Serverless Framework 5. Configure environment protection for prod
Output:
- Complete .github/workflows/deploy.yml
- Multi-stage pipeline
- Integrated test automation
AWS Lambda PHP Patterns
Detailed patterns for implementing AWS Lambda with PHP and Symfony.
Project Structure
Symfony with Bref Structure
my-symfony-lambda/
├── composer.json
├── serverless.yml
├── public/
│ └── index.php # Lambda entry point
├── src/
│ └── Kernel.php # Symfony Kernel
├── config/
│ ├── bundles.php
│ ├── routes.yaml
│ └── services.yaml
└── templates/Raw PHP Structure
my-lambda-function/
├── public/
│ └── index.php # Handler entry point
├── composer.json
├── serverless.yml
└── src/
└── Services/Core Concepts
Cold Start Optimization
PHP cold start depends on framework initialization. Key strategies:
1. Lazy loading - Defer heavy services until needed 2. Disable unused Symfony features - Turn off validation, annotations, etc. 3. Optimize composer autoload - Use classmap for production 4. Use Bref optimized runtime - Leverage PHP 8.x optimizations
Connection Management
// Cache AWS clients at function level
use Aws\DynamoDb\DynamoDbClient;
class DatabaseService
{
private static ?DynamoDbClient $client = null;
public static function getClient(): DynamoDbClient
{
if (self::$client === null) {
self::$client = new DynamoDbClient([
'region' => getenv('AWS_REGION'),
'version' => 'latest'
]);
}
return self::$client;
}
}Environment Configuration
// config/services.yaml
parameters:
env(DATABASE_URL): null
env(APP_ENV): 'dev'
services:
App\Service\Configuration:
arguments:
$tableName: '%env(DATABASE_URL)%'Deployment Options
Quick Start with Serverless Framework
# serverless.yml
service: symfony-lambda-api
provider:
name: aws
runtime: php-82
memorySize: 512
timeout: 20
package:
individually: true
exclude:
- '**/node_modules/**'
- '**/.git/**'
functions:
api:
handler: public/index.php
events:
- http:
path: /{proxy+}
method: ANY
- http:
path: /
method: ANYDeploy with Bref:
composer require bref/bref --dev
vendor/bin/bref deploySymfony Full Configuration
# serverless.yml for Symfony
service: symfony-lambda-api
provider:
name: aws
runtime: php-82
stage: ${self:custom.stage}
region: ${self:custom.region}
environment:
APP_ENV: ${self:custom.stage}
APP_DEBUG: ${self:custom.isLocal}
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
Resource: '*'
functions:
web:
handler: public/index.php
timeout: 30
memorySize: 1024
events:
- http:
path: /{proxy+}
method: ANY
console:
handler: bin/console
timeout: 300
events:
- schedule: rate(1 day)
plugins:
- ./vendor/bref/bref
custom:
stage: dev
region: us-east-1
isLocal: falseImplementation Examples
Symfony with Bref:
// public/index.php
use Bref\Symfony\Bref;
use App\Kernel;
use Symfony\Component\HttpFoundation\Request;
require __DIR__.'/../vendor/autoload.php';
$kernel = new Kernel($_SERVER['APP_ENV'] ?? 'dev', $_SERVER['APP_DEBUG'] ?? true);
$kernel->boot();
$bref = new Bref($kernel);
return $bref->run($event, $context);Raw PHP Handler:
// public/index.php
use function Bref\Lambda\main;
main(function ($event) {
$path = $event['path'] ?? '/';
$method = $event['httpMethod'] ?? 'GET';
return [
'statusCode' => 200,
'body' => json_encode(['message' => 'Hello from PHP Lambda!'])
];
});Raw PHP Lambda Reference
Minimal PHP Lambda handler patterns without framework overhead for maximum performance.
Table of Contents
1. Project Setup 2. Handler Patterns 3. Cold Start Optimization 4. AWS SDK Integration 5. Packaging
---
Project Setup
Basic composer.json
{
"name": "my/lambda-function",
"description": "Raw PHP Lambda",
"require": {
"php": "^8.2",
"bref/bref": "^2.0",
"aws/aws-sdk-php": "^3.300"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"config": {
"optimize-autoloader": true
}
}Project Structure
my-lambda-function/
├── composer.json
├── serverless.yml
├── public/
│ └── index.php
├── src/
│ ├── Handler.php
│ └── Services/
│ └── DynamoDbService.php
└── conf.d/
└── lambda.ini---
Handler Patterns
Basic Request Handler
// public/index.php
use function Bref\Lambda\handler;
handler(function (array $event, $context) {
$path = $event['path'] ?? '/';
$method = $event['httpMethod'] ?? 'GET';
switch ($path) {
case '/health':
return healthCheck();
case '/users':
return handleUsers($method, $event);
default:
return notFound();
}
});
function healthCheck(): array
{
return [
'statusCode' => 200,
'body' => json_encode(['status' => 'ok'])
];
}
function handleUsers(string $method, array $event): array
{
return match($method) {
'GET' => listUsers($event),
'POST' => createUser($event),
default => methodNotAllowed()
};
}
function listUsers(array $event): array
{
return [
'statusCode' => 200,
'body' => json_encode(['users' => []])
];
}
function createUser(array $event): array
{
$body = json_decode($event['body'] ?? '{}', true);
return [
'statusCode' => 201,
'body' => json_encode(['id' => 'new-user-id'])
];
}
function notFound(): array
{
return [
'statusCode' => 404,
'body' => json_encode(['error' => 'Not found'])
];
}
function methodNotAllowed(): array
{
return [
'statusCode' => 405,
'body' => json_encode(['error' => 'Method not allowed'])
];
}PSR-15 Handler
// public/index.php
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Nyholm\Psr7\ServerRequest;
use Nyholm\Psr7\Response;
use function Bref\Lambda\handler;
class PsrHandler implements RequestHandlerInterface
{
public function handle(ServerRequestInterface $request): ResponseInterface
{
$path = $request->getUri()->getPath();
if ($path === '/api/users') {
return new Response(
200,
['Content-Type' => 'application/json'],
json_encode(['users' => []])
);
}
return new Response(404, [], json_encode(['error' => 'Not found']));
}
}
handler(function (array $event, $context) {
$request = ServerRequest::fromArrays(
$event['headers'] ?? [],
[], // query params
$event['body'] ?? null,
$event['httpMethod'] ?? 'GET',
$event['path'] ?? '/'
);
$handler = new PsrHandler();
$response = $handler->handle($request);
return [
'statusCode' => $response->getStatusCode(),
'headers' => $response->getHeaders(),
'body' => (string) $response->getBody()
];
});---
Cold Start Optimization
Lazy Loading Pattern
// src/Services/LazyServiceLoader.php
class LazyServiceLoader
{
private static array $cache = [];
public static function getDynamoDbClient(): \Aws\DynamoDb\DynamoDbClient
{
$key = 'dynamodb';
if (!isset(self::$cache[$key])) {
self::$cache[$key] = new \Aws\DynamoDb\DynamoDbClient([
'region' => getenv('AWS_REGION') ?: 'us-east-1',
'version' => 'latest',
]);
}
return self::$cache[$key];
}
}Singleton Pattern
// src/Services/UserService.php
class UserService
{
private static ?self $instance = null;
private \Aws\DynamoDb\DynamoDbClient $db;
private function __construct()
{
$this->db = LazyServiceLoader::getDynamoDbClient();
}
public static function getInstance(): self
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function getUser(string $id): array
{
$result = $this->db->getItem([
'TableName' => getenv('USERS_TABLE'),
'Key' => ['id' => ['S' => $id]]
]);
return $result['Item'] ?? [];
}
}Module-Level Caching
// public/index.php
// Declare at the top - persists across warm invocations
$dbClient = null;
$tableName = null;
function getDbClient(): \Aws\DynamoDb\DynamoDbClient
{
global $dbClient;
if ($dbClient === null) {
$dbClient = new \Aws\DynamoDb\DynamoDbClient([
'region' => getenv('AWS_REGION') ?: 'us-east-1',
'version' => 'latest',
]);
}
return $dbClient;
}
function getTableName(): string
{
global $tableName;
if ($tableName === null) {
$tableName = getenv('USERS_TABLE') ?: 'users';
}
return $tableName;
}
handler(function (array $event, $context) {
$client = getDbClient();
$table = getTableName();
$result = $client->scan([
'TableName' => $table
]);
return [
'statusCode' => 200,
'body' => json_encode($result['Items'])
];
});---
AWS SDK Integration
DynamoDB Operations
// src/Services/DynamoDbService.php
class DynamoDbService
{
private \Aws\DynamoDb\DynamoDbClient $client;
private string $tableName;
public function __construct(string $tableName)
{
$this->client = new \Aws\DynamoDb\DynamoDbClient([
'region' => getenv('AWS_REGION') ?: 'us-east-1',
'version' => 'latest',
]);
$this->tableName = $tableName;
}
public function get(string $id): ?array
{
$result = $this->client->getItem([
'TableName' => $this->tableName,
'Key' => ['id' => ['S' => $id]]
]);
return $result['Item'] ?? null;
}
public function put(string $id, array $data): void
{
$item = ['id' => ['S' => $id]];
foreach ($data as $key => $value) {
$item[$key] = is_string($value) ? ['S' => $value] : ['N' => (string) $value];
}
$this->client->putItem([
'TableName' => $this->tableName,
'Item' => $item
]);
}
public function delete(string $id): void
{
$this->client->deleteItem([
'TableName' => $this->tableName,
'Key' => ['id' => ['S' => $id]]
]);
}
public function query(string $pk, string $sk = null): array
{
$params = [
'TableName' => $this->tableName,
'KeyConditionExpression' => 'id = :id',
'ExpressionAttributeValues' => [':id' => ['S' => $pk]]
];
if ($sk) {
$params['KeyConditionExpression'] .= ' AND sort = :sort';
$params['ExpressionAttributeValues'][':sort'] = ['S' => $sk];
}
$result = $this->client->query($params);
return $result['Items'] ?? [];
}
}S3 Operations
class S3Service
{
private \Aws\S3\S3Client $client;
private string $bucket;
public function __construct(string $bucket)
{
$this->client = new \Aws\S3\S3Client([
'region' => getenv('AWS_REGION') ?: 'us-east-1',
'version' => 'latest',
]);
$this->bucket = $bucket;
}
public function getObject(string $key): string
{
$result = $this->client->getObject([
'Bucket' => $this->bucket,
'Key' => $key
]);
return (string) $result['Body'];
}
public function putObject(string $key, string $content, string $contentType = 'text/plain'): void
{
$this->client->putObject([
'Bucket' => $this->bucket,
'Key' => $key,
'Body' => $content,
'ContentType' => $contentType
]);
}
}---
Packaging
Serverless Configuration
# serverless.yml
service: raw-php-lambda
provider:
name: aws
runtime: php-82
memorySize: 256
timeout: 10
environment:
AWS_REGION: us-east-1
USERS_TABLE: !Ref UsersTable
functions:
api:
handler: public/index.php
events:
- httpApi:
path: /{proxy+}
method: ANY
- httpApi:
path: /
method: ANY
resources:
Resources:
UsersTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: users
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
plugins:
- ./vendor/bref/brefDeployment
# Install dependencies
composer install --no-dev
# Deploy
vendor/bin/bref deploy---
Error Handling
Structured Error Responses
function handleError(\Throwable $e): array
{
error_log(json_encode([
'error' => $e->getMessage(),
'type' => get_class($e),
'trace' => $e->getTraceAsString()
]));
$statusCode = match (true) {
$e instanceof \InvalidArgumentException => 400,
$e instanceof \RuntimeException => 500,
default => 500
};
return [
'statusCode' => $statusCode,
'body' => json_encode([
'error' => $e->getMessage()
])
];
}
handler(function (array $event, $context) {
try {
// Process request
} catch (\Throwable $e) {
return handleError($e);
}
});---
Logging
Structured Logging
function logRequest(string $level, array $data): void
{
$logData = [
'timestamp' => date('c'),
'level' => $level,
'aws_request_id' => $context->getAwsRequestId(),
...$data
];
error_log(json_encode($logData));
}
// Usage
logRequest('info', [
'event' => 'request_received',
'path' => $event['path'],
'method' => $event['httpMethod']
]);Serverless Deployment Reference
Complete deployment patterns for PHP Lambda functions using Serverless Framework and AWS SAM.
Table of Contents
1. Serverless Framework 2. AWS SAM 3. CI/CD Pipelines 4. Multi-Stage Deployments 5. Custom Domains
---
Serverless Framework
Basic Configuration
# serverless.yml
service: php-lambda-api
provider:
name: aws
runtime: php-82
stage: ${opt:stage, 'dev'}
region: ${opt:region, 'us-east-1'}
memorySize: 512
timeout: 20
environment:
APP_ENV: ${self:provider.stage}
AWS_REGION: ${self:provider.region}
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
Resource: '*'
functions:
api:
handler: public/index.php
description: PHP Lambda API
events:
- httpApi: '*'
plugins:
- ./vendor/bref/brefEnvironment-Specific Settings
# serverless.yml
custom:
stage: ${opt:stage, 'dev'}
# Development settings
dev:
memorySize: 256
timeout: 10
provisioned: 0
# Production settings
prod:
memorySize: 1024
timeout: 30
provisioned: 5
provider:
environment:
STAGE: ${self:custom.stage}
functions:
api:
handler: public/index.php
memorySize: ${self:custom.${self:custom.stage}.memorySize}
timeout: ${self:custom.${self:custom.stage}.timeout}
provisionedConcurrency: ${self:custom.${self:custom.stage}.provisioned}Multiple Functions
functions:
# API function
api:
handler: public/index.php
events:
- httpApi:
path: /{proxy+}
method: ANY
# Background processing
process:
handler: functions/process.php
timeout: 300
events:
- sqs:
arn: !GetAtt MyQueue.Arn
# Scheduled task
cleanup:
handler: functions/cleanup.php
timeout: 900
events:
- schedule: cron(0 3 * * ? *)Layers
# serverless.yml
package:
layers:
- arn:aws:lambda:us-east-1:123456789012:layer:php-extensions:1
functions:
api:
handler: public/index.php
layers:
- arn:aws:lambda:us-east-1:123456789012:layer:php-extensions:1---
AWS SAM
Basic Template
# template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: PHP Lambda API
Parameters:
Stage:
Type: String
Default: dev
AllowedValues:
- dev
- staging
- prod
Globals:
Function:
Runtime: php-82
Timeout: 20
MemorySize: 512
Environment:
Variables:
APP_ENV: !Ref Stage
Resources:
PhpFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./
Handler: public/indexphp
Events:
Api:
Type: HttpApi
Properties:
ApiId: !Ref ApiGateway
Path: /{proxy+}
Method: ANY
RootApi:
Type: HttpApi
Properties:
ApiId: !Ref ApiGateway
Path: /
Method: ANY
ApiGateway:
Type: AWS::ApiGatewayV2::Api
Properties:
ProtocolType: HTTP
StageName: !Ref Stage
UsersTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub users-${Stage}
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
Outputs:
ApiUrl:
Description: API URL
Value: !Sub https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/${Stage}SAM CLI Commands
# Build the function
sam build
# Deploy
sam deploy --guided
# Local testing
sam local start-api---
CI/CD Pipelines
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy PHP Lambda
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Install dependencies
run: composer install --no-interaction
- name: Run tests
run: vendor/bin/phpunit
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Install Serverless
run: npm install -g serverless
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
- name: Deploy to AWS
run: vendor/bin/bref deploy --stage prod
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}GitLab CI
# .gitlab-ci.yml
stages:
- test
- deploy
test:
stage: test
image: php:8.2-cli
script:
- composer install
- vendor/bin/phpunit
deploy:
stage: deploy
image: php:8.2-cli
script:
- npm install -g serverless
- composer install --no-dev
- vendor/bin/bref deploy --stage $CI_ENVIRONMENT_SLUG
environment:
name: review/$CI_COMMIT_REF_SLUG
only:
- develop
except:
- main
deploy-prod:
stage: deploy
image: php:8.2-cli
script:
- npm install -g serverless
- composer install --no-dev
- vendor/bin/bref deploy --stage prod
environment:
name: production
only:
- mainAWS CodePipeline
# buildspec.yml
version: 0.2
phases:
install:
runtime-versions:
php: 8.2
commands:
- composer install --no-dev --optimize-autoloader
build:
commands:
- echo "Building..."
post_build:
commands:
- vendor/bin/bref deploy --stage ${STAGE}
env:
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}---
Multi-Stage Deployments
Environment Configuration
# serverless.yml
custom:
environments:
dev:
domain: dev-api.example.com
stage: dev
staging:
domain: staging-api.example.com
stage: staging
prod:
domain: api.example.com
stage: prod
provider:
stage: ${self:custom.environments.${self:provider.stage}.stage}
functions:
api:
handler: public/index.php
events:
- httpApi:
path: /{proxy+}
method: ANY
authorizer:
type: jwt
identitySource: $request.header.Authorization
jwt:
audience:
- ${self:custom.environments.${self:provider.stage}.clientId}
issuer:
- https://${self:custom.environments.${self:provider.stage}.authDomain}Deployment Commands
# Deploy to dev
vendor/bin/bref deploy --stage dev
# Deploy to staging
vendor/bin/bref deploy --stage staging
# Deploy to production
vendor/bin/bref deploy --stage prod---
Custom Domains
Serverless Domain Plugin
# serverless.yml
plugins:
- ./vendor/bref/bref
- serverless-domain-manager
custom:
customDomain:
domainName: api.example.com
stage: ${self:provider.stage}
basePath: ''
certificateArn: arn:aws:acm:us-east-1:123456789012:certificate/cert-id
createRoute53Record: trueAPI Gateway Custom Domain
# serverless.yml
resources:
Resources:
ApiDomain:
Type: AWS::ApiGatewayV2::DomainName
Properties:
DomainName: api.example.com
DomainNameConfigurations:
- CertificateArn: arn:aws:acm:us-east-1:123456789012:certificate/cert-id
EndpointType: REGIONAL
SecurityPolicy: TLS_1_2---
Monitoring
CloudWatch Logs
# serverless.yml
functions:
api:
handler: public/index.php
loggingConfig:
level: error
retentionInDays: 7X-Ray Tracing
# serverless.yml
provider:
tracing:
api: true
functions:
api:
handler: public/index.php
tracing: ActiveTesting Lambda Reference
Patterns for testing PHP Lambda functions including unit tests, integration tests, and local development.
Table of Contents
1. Unit Testing 2. Integration Testing 3. Local Development 4. Mocking AWS Services
---
Unit Testing
PHPUnit Configuration
<!-- phpunit.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
cacheDirectory=".phpunit.cache">
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Integration">
<directory>tests/Integration</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>src</directory>
</include>
</source>
</phpunit>Basic Unit Test
// tests/Unit/UserServiceTest.php
<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use App\Services\UserService;
use App\Services\DynamoDbService;
class UserServiceTest extends TestCase
{
private UserService $service;
private $mockDb;
protected function setUp(): void
{
parent::setUp();
// Create mock for DynamoDB service
$this->mockDb = $this->createMock(DynamoDbService::class);
$this->service = new UserService($this->mockDb);
}
public function testGetUserReturnsUserData(): void
{
$userId = 'user-123';
$expectedData = ['id' => $userId, 'name' => 'Test User'];
$this->mockDb->expects($this->once())
->method('get')
->with($userId)
->willReturn($expectedData);
$result = $this->service->getUser($userId);
$this->assertEquals($expectedData, $result);
}
public function testCreateUserReturnsNewId(): void
{
$userData = ['name' => 'New User'];
$this->mockDb->expects($this->once())
->method('put')
->willReturnCallback(function ($id, $data) {
$this->assertNotEmpty($id);
$this->assertEquals('New User', $data['name']);
});
$result = $this->service->createUser($userData);
$this->assertNotEmpty($result['id']);
}
public function testGetUserThrowsExceptionForInvalidId(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('User ID is required');
$this->service->getUser('');
}
}Testing Handler Logic
// tests/Unit/HandlerTest.php
<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
class HandlerTest extends TestCase
{
public function testHealthCheckReturnsOk(): void
{
$event = [
'path' => '/health',
'httpMethod' => 'GET'
];
$result = handleHealthCheck($event);
$this->assertEquals(200, $result['statusCode']);
$this->assertJson($result['body']);
}
public function testGetUsersReturnsUserList(): void
{
$event = [
'path' => '/users',
'httpMethod' => 'GET'
];
$result = handleUsers('GET', $event, []);
$this->assertEquals(200, $result['statusCode']);
$body = json_decode($result['body'], true);
$this->assertArrayHasKey('users', $body);
}
public function testCreateUserReturnsCreatedStatus(): void
{
$event = [
'path' => '/users',
'httpMethod' => 'POST',
'body' => json_encode(['name' => 'Test User'])
];
$result = handleUsers('POST', $event, []);
$this->assertEquals(201, $result['statusCode']);
$body = json_decode($result['body'], true);
$this->assertArrayHasKey('id', $body);
}
public function testInvalidPathReturns404(): void
{
$event = [
'path' => '/invalid',
'httpMethod' => 'GET'
];
$result = handleRequest($event, []);
$this->assertEquals(404, $result['statusCode']);
}
}---
Integration Testing
Testing with LocalStack
# docker-compose.yml
version: '3.8'
services:
localstack:
image: localstack/localstack:latest
ports:
- "4566:4566"
environment:
SERVICES: dynamodb,s3
DEFAULT_REGION: us-east-1
volumes:
- localstack-data:/var/lib/localstack
php:
build: .
depends_on:
- localstack
environment:
AWS_ACCESS_KEY_ID: test
AWS_SECRET_ACCESS_KEY: test
AWS_REGION: us-east-1
DYNAMODB_ENDPOINT: http://localstack:4566Integration Test Example
// tests/Integration/UserServiceIntegrationTest.php
<?php
namespace Tests\Integration;
use PHPUnit\Framework\TestCase;
use App\Services\DynamoDbService;
use App\Services\UserService;
class UserServiceIntegrationTest extends TestCase
{
private UserService $service;
private string $tableName = 'test-users';
protected function setUp(): void
{
parent::setUp();
// Use local DynamoDB for testing
$endpoint = getenv('DYNAMODB_ENDPOINT') ?: 'http://localhost:4566';
$dbService = new DynamoDbService($this->tableName, $endpoint);
$this->service = new UserService($dbService);
// Create table if not exists
$this->createTable();
}
private function createTable(): void
{
$client = new \Aws\DynamoDb\DynamoDbClient([
'region' => 'us-east-1',
'endpoint' => getenv('DYNAMODB_ENDPOINT'),
'credentials' => [
'key' => 'test',
'secret' => 'test'
]
]);
try {
$client->createTable([
'TableName' => $this->tableName,
'KeySchema' => [
['AttributeName' => 'id', 'KeyType' => 'HASH']
],
'AttributeDefinitions' => [
['AttributeName' => 'id', 'AttributeType' => 'S']
],
'BillingMode' => 'PAY_PER_REQUEST'
]);
} catch (\Aws\DynamoDb\Exception\ResourceInUseException $e) {
// Table already exists
}
}
public function testFullUserLifecycle(): void
{
// Create
$user = $this->service->createUser([
'name' => 'Test User',
'email' => 'test@example.com'
]);
$this->assertNotEmpty($user['id']);
// Read
$found = $this->service->getUser($user['id']);
$this->assertEquals('Test User', $found['name']);
// Update
$updated = $this->service->updateUser($user['id'], ['name' => 'Updated']);
$this->assertEquals('Updated', $updated['name']);
// Delete
$this->service->deleteUser($user['id']);
$this->assertNull($this->service->getUser($user['id']));
}
protected function tearDown(): void
{
// Clean up test table
parent::tearDown();
}
}---
Local Development
Serverless Offline
# Install serverless-offline
composer require bref/serverless-offline --dev# serverless.yml
plugins:
- ./vendor/bref/bref
- ./vendor/bref/serverless-offline/plugin.yml
functions:
api:
handler: public/index.php# Run locally
vendor/bin/serverless offline startPHP Built-in Server
// public/index.php
use Symfony\Component\HttpFoundation\Request;
// Check if running locally
if (php_sapi_name() === 'cli-server') {
$request = Request::createFromGlobals();
// Handle request directly
echo handleRequest($request);
exit;
}# Start local server
php -S localhost:8000 -t public/---
Mocking AWS Services
Using Mockery
// tests/Mocks/AwsMocks.php
<?php
namespace Tests\Mocks;
use Aws\Result;
use Mockery;
class AwsMocks
{
public static function dynamoDbGetItem(array $item): Result
{
return new Result([
'Item' => $item
]);
}
public static function dynamoDbPutItem(): Result
{
return new Result([
'Attributes' => [
'id' => ['S' => 'test-id']
]
]);
}
public static function dynamoDbDeleteItem(): Result
{
return new Result([]);
}
public static function s3GetObject(string $content): Result
{
return new Result([
'Body' => Mockery::mock('GuzzleHttp\Psr7\Stream')
->shouldReceive('getContents')
->andReturn($content)
->getMock()
]);
}
}Mocking in Tests
// tests/Unit/UserServiceWithMocksTest.php
<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use Aws\Result;
use App\Services\UserService;
use App\Services\DynamoDbService;
use Tests\Mocks\AwsMocks;
class UserServiceWithMocksTest extends TestCase
{
public function testGetUserWithMockedDynamoDb(): void
{
$mockDb = $this->createMock(DynamoDbService::class);
$mockDb->method('get')
->willReturn(AwsMocks::dynamoDbGetItem([
'id' => ['S' => 'user-123'],
'name' => ['S' => 'Test User']
]));
$service = new UserService($mockDb);
$result = $service->getUser('user-123');
$this->assertEquals('user-123', $result['id']);
$this->assertEquals('Test User', $result['name']);
}
}---
Test Coverage
Running Tests
# Run all tests
vendor/bin/phpunit
# Run specific test suite
vendor/bin/phpunit --testsuite=Unit
# Run with coverage
vendor/bin/phpunit --coverage-html coverageCI Integration
# .github/workflows/test.yml
- name: Run tests
run: vendor/bin/phpunit --coverage-text
- name: Upload coverage
if: github.event_name == 'pull_request'
uses: codecov/codecov-action@v3
with:
files: ./coverage.xml---
Performance Testing
Cold Start Testing
<?php
// Benchmark cold start
$times = [];
for ($i = 0; $i < 10; $i++) {
// Simulate cold start by clearing opcache
if (function_exists('opcache_reset')) {
opcache_reset();
}
$start = microtime(true);
// Initialize application
require 'vendor/autoload.php';
$app = require 'config/bootstrap.php';
$end = microtime(true);
$times[] = ($end - $start) * 1000;
// Wait between tests
sleep(2);
}
echo "Average cold start: " . (array_sum($times) / count($times)) . "ms\n";
echo "Min: " . min($times) . "ms\n";
echo "Max: " . max($times) . "ms\n";Related skills
Forks & variants (1)
Aws Lambda Php Integration has 1 known copy in the catalog totaling 20 installs. They canonicalize to this original listing.
- giuseppe-trisciuoglio - 20 installs
How it compares
Use for Bref-specific PHP Lambda sizing and packaging when generic AWS Lambda guides omit Symfony cold-start and Composer deployment limits.
FAQ
What does aws-lambda-php-integration do?
Provides AWS Lambda integration patterns for PHP with Symfony using the Bref framework. Creates Lambda handler classes, configures runtime layers, sets up SQS/SNS event.
When should I use aws-lambda-php-integration?
User deploying PHP/Symfony applications to AWS Lambda, configuring API Gateway integration, implementing serverless PHP applications, or optimizing Lambda performance with Bref.
Is aws-lambda-php-integration safe to install?
Review the Security Audits panel on this page before installing in production.