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

Fun Laravel Package

php-standard-library/fun

Functional programming utilities for PHP: compose and pipe callables, decorate functions, and control execution (memoize, throttle, debounce, retry, etc.). Part of PHP Standard Library with focused, reusable helpers for cleaner functional-style code.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require php-standard-library/fun
    

    No Laravel-specific configuration is needed—it integrates seamlessly with PHP closures and Laravel’s service container.

  2. First Use Case: Middleware Decorator Replace a traditional middleware class with a functional decorator:

    use Fun\Decorators\decorate;
    use Illuminate\Http\Request;
    
    $middleware = decorate(
        fn(Request $request) => $request->next($request),
        fn($next) => fn(Request $request) =>
            logger()->info('Request started') &&
            $next($request) &&
            logger()->info('Request completed')
    );
    
  3. Where to Look First

    • Core Classes:
      • Fun\Compose (for pipe, tap, compose).
      • Fun\Control (for try, retry, race).
      • Fun\Decorators (for decorate, memoize, timeout).
    • Laravel Synergy: Use with Laravel’s app() for dependency injection:
      $decoratedService = decorate(
          app()->make(MyService::class),
          fn($next) => fn() => logger()->debug('Service called') && $next()
      );
      

Implementation Patterns

1. Middleware Composition

Workflow: Replace Laravel’s Kernel::middleware() groups with functional decorators.

// app/Http/Kernel.php (partial)
protected $middlewareGroups = [
    'web' => [
        decorate(
            fn($request) => $request->next($request),
            fn($next) => fn($request) =>
                auth()->check() || redirect('/login'),
            fn($next) => fn($request) =>
                $next($request)->header('X-Processed', 'true')
        ),
    ],
];

2. Service Layer Decorators

Pattern: Decorate repositories/services with cross-cutting concerns.

// app/Services/UserService.php
$userService = decorate(
    app()->make(UserRepository::class),
    fn($next) => fn($userId) =>
        cache()->remember("user:$userId", 60, fn() => $next($userId)),
    fn($next) => fn($userId) =>
        logger()->info("Fetching user $userId") && $next($userId)
);

3. Job/Command Pipelines

Use Case: Chain pre/post-processing in Laravel jobs or Artisan commands.

// app/Jobs/ProcessOrder.php
public function handle() {
    $result = pipe(
        $this->order,
        fn($order) => $order->validate(),
        fn($order) => $order->charge(),
        fn($order) => $order->notify(),
        fn($order) => $order->archive()
    );
}

4. Event Listener Composition

Pattern: Compose event listeners into pipelines.

// EventServiceProvider
protected $listen = [
    'order.placed' => [
        decorate(
            fn($event) => null,
            fn($next) => fn($event) =>
                $this->logOrder($event) && $next($event),
            fn($next) => fn($event) =>
                $this->sendNotification($event) && $next($event)
        ),
    ],
];

5. API Request/Response Transformation

Integration Tip: Use pipe to transform requests/responses in route middleware.

// app/Http/Middleware/TransformResponse.php
public function handle($request, Closure $next) {
    return pipe(
        $next($request),
        fn($response) => $response->header('X-API-Version', 'v1'),
        fn($response) => $response->json(['data' => $response->original])
    );
}

6. Testing Helpers

Pattern: Create reusable test decorators.

// tests/TestHelpers.php
function mockWithRetry($closure, $maxAttempts = 3) {
    return retry($closure, $maxAttempts);
}

// tests/Feature/OrderTest.php
test('order processing retries on failure', function() {
    mockWithRetry(fn() => $this->failOrder())->shouldBeCalled();
});

Gotchas and Tips

Pitfalls

  1. Closure Scope Issues

    • Problem: Capturing variables in closures can lead to unexpected behavior.
    • Fix: Use use ($var) explicitly or leverage Fun\Compose::curry for partial application.
      // Bad: Implicit capture
      $userId = 1;
      $getUser = fn() => User::find($userId); // $userId might change!
      
      // Good: Explicit or curried
      $getUser = curry(fn($id) => User::find($id))($userId);
      
  2. Debugging Composed Functions

    • Problem: Stack traces for composed functions are harder to follow.
    • Tip: Use Fun\Compose::tap to log intermediate steps:
      $result = tap(
          $composedFunction,
          fn($step) => logger()->debug("Step: $step")
      );
      
  3. Performance Overhead

    • Gotcha: Deep composition (e.g., 10+ decorators) can slow down execution.
    • Tip: Benchmark with blackfire.io and limit decorators to 3–5 per pipeline.
  4. Laravel Container Conflicts

    • Problem: Decorating container-bound classes may cause circular references.
    • Fix: Use app()->make() inside decorators or bind decorated versions explicitly:
      $app->bind(MyService::class, fn($app) =>
          decorate($app->make(MyService::class), /* ... */)
      );
      
  5. Async/Await Limitations

    • Gotcha: Fun\Control does not support native PHP async/await.
    • Workaround: Use Spatie\Async or Amp for async workflows.

Debugging Tips

  • Log Decorator Execution:
    $decorated = decorate(
        $original,
        fn($next) => fn($arg) =>
            logger()->debug("Before: $arg") &&
            $next($arg) &&
            logger()->debug("After: $arg")
    );
    
  • Use Fun\Compose::inspect:
    $composed = inspect($addFive, $multiplyByTwo);
    // Outputs: [Function#0, Function#1]
    

Configuration Quirks

  • No Laravel-Specific Config: The package is agnostic to Laravel’s config system. Store decorator logic in:
    • Service providers (boot() method).
    • Facades or helpers (e.g., app/Helpers/fun.php).
  • Type Safety: Use PHP 8.1+ attributes or PHPStan to enforce types in composed functions.

Extension Points

  1. Custom Decorators Extend Fun\Decorators\Decorator to create domain-specific decorators:

    class CacheDecorator extends Decorator {
        public function __invoke($next) {
            return fn($key) =>
                cache()->remember($key, 60, fn() => $next($key));
        }
    }
    
  2. Laravel Facade Wrapper Create a facade to integrate with Laravel’s conventions:

    // app/Facades/Fun.php
    class Fun extends Facade {
        protected static function getFacadeAccessor() {
            return 'fun';
        }
    }
    

    Bind it in a service provider:

    $app->singleton('fun', fn() => new Fun\Fun());
    
  3. Event Decorators Decorate Laravel events for side effects:

    Event::listen('order.created', decorate(
        fn($event) => null,
        fn($next) => fn($event) =>
            $this->dispatch(new OrderCreatedEvent($event->order)),
        fn($next) => fn($event) =>
            $this->logEvent($event)
    ));
    

Pro Tips

  • Combine with Laravel’s pipe():
    use Illuminate\Pipeline\Pipeline;
    
    $result = resolve(Pipeline::class)
        ->send($request)
        ->through([$middleware1, $middleware2])
        ->thenReturn();
    
  • Memoization for Expensive Calls:
    $expensiveCall = memoize(fn() => $this->fetchDataFromExternalApi());
    
  • Timeout Decorators:
    $timeoutCall = timeout(fn() => $this->slowOperation(), 5); // 5 seconds
    
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.
codraw/graphviz
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata