tourze / symfony-aop-bundle
AOP for Symfony Framework
Requires
- php: ^8.1
- friendsofphp/proxy-manager-lts: ^1.0.18
- symfony/console: ^6.4 || ^7.1
- symfony/expression-language: ^6.4 || ^7.1
- symfony/framework-bundle: ^6.4
- symfony/stopwatch: ^6.4 || ^7.1
- symfony/yaml: ^6.4 || ^7.1
- tourze/arrayable: 0.0.*
This package is auto-updated.
Last update: 2025-03-29 10:40:34 UTC
README
Overview
AopBundle is a Symfony bundle that implements Aspect-Oriented Programming (AOP) using PHP 8's Attribute features. It enables adding cross-cutting concerns (like logging, caching, transactions) to your code without modifying the core logic.
Requirements
- PHP 8.1+
- Symfony 6.4+
Installation
composer require tourze/symfony-aop-bundle
Features
- Define aspects using PHP 8 attributes
- Support for multiple advice types (Before, After, AfterReturning, AfterThrowing)
- Join point context with access to method parameters and return values
- Powerful pointcut expressions for targeting specific services/methods
- Built-in stopwatch support for performance monitoring
- Exception handling capabilities
Basic Usage
1. Define an Aspect
Create a class with the #[Aspect]
attribute and define advice methods:
<?php namespace App\Aspect; use Tourze\Symfony\Aop\Attribute\Aspect; use Tourze\Symfony\Aop\Attribute\Before; use Tourze\Symfony\Aop\Model\JoinPoint; #[Aspect] class LoggingAspect { #[Before('class.getName() === "App\\Service\\UserService" && method.getName() === "createUser"')] public function logBefore(JoinPoint $joinPoint): void { // Logging logic before method execution } }
2. Available Advice Types
#[Before]
- Executed before the target method#[After]
- Executed after the target method (regardless of exceptions)#[AfterReturning]
- Executed after successful method return#[AfterThrowing]
- Executed when the target method throws an exception#[CatchException]
- Used for exception handling
3. JoinPoint
The JoinPoint
object provides context for the intercepted method:
$joinPoint->getInstance(); // The service instance $joinPoint->getMethod(); // Method name being executed $joinPoint->getParams(); // Method parameters $joinPoint->getReturnValue(); // Return value (for after advice) $joinPoint->getException(); // Exception (for exception advice) $joinPoint->proceed(); // Manually execute the original method
4. Pointcut Expressions
Define where advice should be applied:
// Match by service ID #[Before(serviceIds: ['app.user_service'])] // Match by class attribute #[AfterThrowing(classAttribute: CatchException::class)] // Match by method attribute #[After(methodAttribute: SomeAttribute::class)] // Match by service tags #[Before(serviceTags: ['app.loggable'])] // Match by parent class #[Before(parentClasses: [BaseRepository::class])] // Custom expression #[Before('class.getName() === "App\\Service\\UserService"')]
5. Performance Monitoring
use Tourze\Symfony\Aop\Attribute\Stopwatch; class UserService { #[Stopwatch] public function complexOperation() { // Time-consuming operation } }
Best Practices
-
Keep aspects focused
- Each aspect should have a single responsibility
- Avoid heavy operations in advice methods
-
Advice execution order
- Before advice is executed in declaration order
- After/AfterReturning/AfterThrowing advice is executed in reverse order
-
Performance considerations
- Use AOP only when necessary
- Consider the performance impact in production
- Use Stopwatch to monitor method execution time
-
Exception handling
- Be careful with exception handling in advice
- Consider using AfterThrowing for exception logging
- Use CatchException for controlled exception handling
Configuration
No additional configuration is required. The bundle automatically detects services with the #[Aspect]
attribute and applies advice to matching services.
Contributing
Contributions are welcome. Please feel free to submit a Pull Request.
License
This bundle is available under the MIT license. See the LICENSE file for more information.