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.
- PHP 8.1+
- Symfony 6.4+
composer require tourze/symfony-aop-bundle
- 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
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
}
}
#[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
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
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"')]
use Tourze\Symfony\Aop\Attribute\Stopwatch;
class UserService
{
#[Stopwatch]
public function complexOperation()
{
// Time-consuming operation
}
}
-
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
No additional configuration is required. The bundle automatically detects services with the #[Aspect]
attribute and applies advice to matching services.
Contributions are welcome. Please feel free to submit a Pull Request.
This bundle is available under the MIT license. See the LICENSE file for more information.