Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Go Aop Php Laravel Package

lisachenko/go-aop-php

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require goaop/framework
    
  2. Create an Aspect Kernel Extend Go\Core\AspectKernel in app/ApplicationAspectKernel.php:

    use Go\Core\AspectKernel;
    
    class ApplicationAspectKernel extends AspectKernel {
        protected function configureAop(AspectContainer $container): void {
            // Register aspects here
        }
    }
    
  3. Initialize the Kernel In your front controller (e.g., public/index.php):

    $kernel = ApplicationAspectKernel::getInstance();
    $kernel->init([
        'debug' => true,
        'appDir' => __DIR__ . '/..',
        'cacheDir' => __DIR__ . '/runtime/aop_cache',
        'includePaths' => [__DIR__ . '/../src']
    ]);
    
  4. Define an Aspect Create a class implementing Go\Aop\Aspect with advice methods:

    use Go\Aop\Aspect;
    use Go\Lang\Attribute\Before;
    
    class LoggingAspect implements Aspect {
        #[Before("execution(public *->save(..))")]
        public function logSave(MethodInvocation $invocation) {
            echo "Saving: " . $invocation->getMethod()->getName() . "\n";
        }
    }
    
  5. Register the Aspect In configureAop():

    $container->registerAspect(new LoggingAspect());
    

First Use Case

Log all method calls in a service layer:

// Aspect/LoggerAspect.php
#[Before("execution(*->*(..))")]
public function logMethod(MethodInvocation $invocation) {
    $class = $invocation->getThis()->getClass()->getName();
    $method = $invocation->getMethod()->getName();
    file_put_contents('method_log.txt', "$class::$method\n", FILE_APPEND);
}

Implementation Patterns

Core Workflows

1. Aspect Registration & Pointcuts

  • Register aspects in configureAop():
    $container->registerAspect(new SecurityAspect());
    $container->registerAspect(new CachingAspect());
    
  • Define pointcuts using expressive syntax:
    // Target all public methods in UserService
    #[Before("execution(public UserService->*(..))")]
    
    // Target methods annotated with @Cacheable
    #[Before("@annotation(Cacheable)")]
    

2. Advice Types

  • Before: Run logic before method execution.
    #[Before("execution(*->validate(..))")]
    public function validateInput(MethodInvocation $invocation) {
        $args = $invocation->getArguments();
        if (empty($args[0])) throw new InvalidArgumentException();
    }
    
  • Around: Wrap method execution (e.g., for caching).
    #[Around("execution(*->fetch(..))")]
    public function cacheFetch(ProceedingJoinPoint $pjp) {
        $cacheKey = md5($pjp->getMethod()->getName() . serialize($pjp->getArguments()));
        if (cache()->has($cacheKey)) {
            return cache()->get($cacheKey);
        }
        $result = $pjp->proceed();
        cache()->put($cacheKey, $result, 3600);
        return $result;
    }
    
  • After: Run cleanup logic.
    #[After("execution(*->*(..))")]
    public function logExecutionTime(MethodInvocation $invocation) {
        $time = microtime(true) - $invocation->getStartTime();
        Logger::info("Method {$invocation->getMethod()} took {$time}s");
    }
    

3. Property Interception (PHP 8.4+)

  • Intercept property access in aspects:
    use Go\Aop\Intercept\FieldAccess;
    
    #[Before("fieldAccess(*->userName)")]
    public function logPropertyAccess(FieldAccess $access) {
        echo "Accessing userName: " . $access->getField()->getName() . "\n";
    }
    

4. Introductions (Interface Injection)

  • Add interfaces to classes dynamically:
    #[Introduce("interface Serializable")]
    public function serialize($object): string {
        return serialize($object->getData());
    }
    
    #[Introduce("interface Serializable")]
    public function unserialize(string $serialized): void {
        $object->setData(unserialize($serialized));
    }
    

Integration Tips

Laravel Integration

  1. Service Provider Setup:

    // app/Providers/AopServiceProvider.php
    use Go\Core\AspectKernel;
    
    class AopServiceProvider extends ServiceProvider {
        public function register() {
            $kernel = ApplicationAspectKernel::getInstance();
            $kernel->init([
                'debug' => config('app.debug'),
                'appDir' => base_path(),
                'cacheDir' => storage_path('framework/aop_cache'),
                'includePaths' => [app_path(), database_path()]
            ]);
        }
    }
    
  2. Register in config/app.php:

    'providers' => [
        // ...
        App\Providers\AopServiceProvider::class,
    ],
    

Testing Aspects

  • Mock JoinPoints:

    $invocation = $this->createMock(MethodInvocation::class);
    $invocation->method('getMethod')->willReturn(new ReflectionMethod(User::class, 'save'));
    $invocation->method('getArguments')->willReturn([$user]);
    
    $aspect = new LoggingAspect();
    $aspect->logSave($invocation);
    
  • Test Pointcut Matching:

    $pointcut = new Pointcut("execution(public *->save(..))");
    $this->assertTrue($pointcut->matches(new MethodJoinPoint(User::class, 'save')));
    

Performance Optimization

  • Cache Configuration:
    $kernel->init([
        'cacheDir' => storage_path('framework/aop_cache'),
        'cacheTTL' => 3600, // Cache weaved classes for 1 hour
    ]);
    
  • Exclude Paths:
    'excludePaths' => [
        storage_path('framework/views'),
        storage_path('framework/cache'),
    ],
    

Gotchas and Tips

Pitfalls

  1. Private Method Interception

    • Intercepting private methods requires explicit pointcut syntax:
      #[Before("execution(private *->*(..))")]
      
    • Warning: Overusing private method interception can break encapsulation. Prefer public/protected methods where possible.
  2. Final Classes/Methods

    • Go! AOP can intercept final classes/methods, but be cautious:
      • Intercepting final methods may cause unexpected behavior in child classes.
      • Use @annotation or @within pointcuts for safer targeting:
        #[Before("@annotation(Loggable)")]
        
  3. Property Interception Limitations (PHP 8.4+)

    • Unsupported:
      • static, readonly, or inherited private/final properties.
      • Array-typed properties only support get hooks (no set).
    • Workaround: Use Around advice for full control:
      #[Around("fieldAccess(*->items)")]
      public function interceptArrayAccess(ProceedingFieldJoinPoint $pjp) {
          $value = $pjp->proceed();
          if ($pjp->getAccessType() === FieldAccessType::WRITE) {
              // Custom logic for writes
          }
          return $value;
      }
      
  4. Circular Dependencies

    • Aspects cannot depend on each other directly. Use composition or service containers (e.g., Laravel’s DI) to share logic.
    • Error: Aspect A depends on Aspect B, which depends on Aspect A → Refactor to avoid mutual initialization.
  5. Debugging Weaved Code

    • XDebug Tip: Set breakpoints in the original source files, not the weaved cache. Go! AOP preserves line numbers and source maps.
    • Cache Invalidation: Clear the cache (rm -rf storage/framework/aop_cache/*) if aspects aren’t applying:
      php artisan cache:clear
      

Debugging Tips

  1. Enable Debug Mode

    $kernel->init(['debug' => true]);
    
    • Logs weaved classes to cacheDir/weaved/.
    • Outputs pointcut matching details to stderr.
  2. Inspect Weaved Classes

    • Check generated proxy classes in cacheDir/weaved/.
    • Use php -r 'var_dump(class_uses(\App\Models\User::class));' to see applied traits.
  3. Pointcut Debugging

    • Test pointcuts interactively:
      $pointcut = new Pointcut("execution(*->*(..))");
      var_dump($pointcut->matches(new MethodJoinPoint(User::class, '
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor
spatie/laravel-javascript-views