goaop / goaop-laravel-bridge
Integration bridge for Go! AOP framework
Fund package maintenance!
Requires
- php: ^8.4
- goaop/framework: ^4.0@dev
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.5
This package is auto-updated.
Last update: 2026-08-01 16:03:08 UTC
README
Integration bridge for the Go! AOP framework and Laravel. It boots the AOP engine early in the application lifecycle so aspects are woven into your classes transparently — no code generation steps, no manual proxies.
Why Aspect-Oriented Programming in Laravel?
Some logic doesn't belong to any single class, yet ends up copied into hundreds of them: logging, caching, metrics, transactions, authorization checks, rate limiting, retry policies. Laravel's middleware solves this for HTTP requests — AOP solves it for any method in your codebase. Define the behavior once as an aspect, declare where it applies with a pointcut expression, and the engine weaves it in automatically. Your services stay pure business logic.
✨ Highlights
- 🪡 Transparent weaving — aspects are applied by transforming classes at load time. No base classes to extend, no interfaces to implement, no
Proxywrappers to maintain, no changes to how younewor inject your services. - 🏷️ Modern PHP 8 attributes — advices are declared with
#[Before],#[After],#[Around]and#[AfterThrowing]right on your aspect methods, with a powerful regexp-like pointcut syntax (execution(public App\Services\**->*(*))). - 🧩 Laravel-native integration — package auto-discovery, publishable config, aspects resolved through the container (constructor DI works), registration via a simple config list or the
goaop.aspectservice tag,php artisan aboutsupport. - 🚀 Production-friendly — pre-generate all proxies at deploy time with
php artisan aop:warmup; withdebugoff the woven code is served straight from cache and plays nicely with opcache. - 🔬 Pure PHP, no magic runtime — built on Go! AOP 4.x: no PECL extensions, no
eval(), all transformations produce reviewable static PHP files. - ✅ Proven by tests — the bridge ships with end-to-end weaving tests (advice execution,
Aroundreturn rewriting, cache generation) running against Laravel 12 and 13 on PHP 8.4.
Requirements
- PHP >= 8.4
- Laravel 12 or 13
- goaop/framework 4.x (attribute-based aspects)
Installation
composer require goaop/goaop-laravel-bridge
The service provider is registered automatically via package discovery.
Note Until goaop/framework 4.0 is tagged, the bridge depends on the unreleased
4.0-devline, so your application'scomposer.jsonneeds:"minimum-stability": "dev", "prefer-stable": true
Publish the configuration if you want to tweak it:
php artisan vendor:publish --tag=goaop-config
Defining an aspect
Aspects are plain classes implementing Go\Aop\Aspect whose advice methods are declared with PHP 8 attributes (#[Before], #[After], #[Around], #[AfterThrowing]):
<?php namespace App\Aspects; use Go\Aop\Aspect; use Go\Aop\Intercept\MethodInvocation; use Go\Lang\Attribute\Around; use Go\Lang\Attribute\Before; use Illuminate\Support\Facades\Log; class LoggingAspect implements Aspect { #[Before('execution(public App\Services\**->*(*))')] public function logMethodCall(MethodInvocation $invocation): void { Log::debug('Calling ' . $invocation->getMethod()->getName()); } #[Around('execution(public App\Services\PaymentService->charge(*))')] public function measureCharge(MethodInvocation $invocation): mixed { $start = hrtime(true); try { return $invocation->proceed(); } finally { Log::info('charge() took ' . (hrtime(true) - $start) / 1e6 . 'ms'); } } }
See the Go! AOP documentation on core concepts and creating aspects for the full pointcut expression syntax.
Auto-discovery of aspects
You never register aspects with the AOP engine manually. During the application's boot phase — after all service providers have registered, before your application code runs — the bridge collects aspects from two sources and hands each of them to the engine's aspect container:
-
The
go_aop.aspectsconfig list. Every class listed here is resolved through the Laravel service container, so constructor dependency injection works out of the box:// config/go_aop.php 'aspects' => [ App\Aspects\LoggingAspect::class, ],
-
The
goaop.aspectcontainer tag. Any service tagged withgoaop.aspectin one of your service providers is picked up automatically — useful when an aspect needs non-trivial construction logic, or when a package wants to contribute aspects without touching your config:// app/Providers/AppServiceProvider.php — in register() $this->app->singleton(LoggingAspect::class, function ($app) { return new LoggingAspect($app->make(LoggerInterface::class)); }); $this->app->tag([LoggingAspect::class], 'goaop.aspect');
Both sources can be combined; duplicates are registered only once. Every discovered class must implement Go\Aop\Aspect, otherwise the bridge fails fast with a descriptive exception. Once registered, the engine reads the #[Before]/#[After]/#[Around]/#[AfterThrowing] attributes from the aspect's methods and weaves the advices into every class matched by their pointcut expressions as it is loaded (or ahead of time via aop:warmup).
Configuration
Key options in config/go_aop.php (all overridable via env):
| Option | Default | Purpose |
|---|---|---|
debug |
GOAOP_DEBUG → APP_DEBUG |
Re-weave when sources change; keep off in production |
appDir |
base_path() |
Root directory the weaver may touch |
cacheDir |
storage_path('framework/aop') (GOAOP_CACHE_DIR) |
Where woven sources and proxies are cached |
cacheFileMode |
0770 (GOAOP_CACHE_PERMISSIONS, octal digits, e.g. "770") |
chmod for cache files |
includePaths |
[app_path()] |
Only these directories are woven |
excludePaths |
[] |
Never weave these |
features |
0 (GOAOP_FEATURES) |
Bitmask of Go\Aop\Features engine features |
aspects |
[] |
Aspect classes to auto-register |
Deployment
Weaving happens lazily on first load of each class. To pre-generate all proxies during deployment (recommended with debug => false):
php artisan aop:warmup
php artisan about shows the current AOP cache location and debug mode.
Caveats
- Weaving starts at the beginning of the application's boot phase. Classes that are already loaded before that (very early bootstrap code, other packages'
register()internals) cannot be woven. - Only classes under
appDir+includePathsare considered — vendor code is not woven. - Exception handlers are best excluded via
excludePaths: when a fatal error occurs, a woven handler may not be loadable from a cold cache.
License
MIT — see LICENSE.