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

Later Laravel Package

sanmai/later

Later is a tiny PHP library for scheduling delayed callbacks and lightweight task execution. Queue functions to run after a given time, manage timers, and build simple background jobs without a full framework. Useful for CLI daemons and event loops.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer:

composer require sanmai/later

First use case: Defer computation until needed (e.g., expensive API calls, heavy data processing).

use function Later\later;

$deferredUser = later(function () {
    return User::with('posts')->find(1);
});

// Access only when required (e.g., in a view or late-bound method)
$posts = $deferredUser->get()->posts;

Key entry points:

  1. later() – Wrap a generator function.
  2. lazy() – Convert an existing iterable (e.g., array) into a deferred object.
  3. now() – Force immediate evaluation (for cached/precomputed results).

Laravel-specific tip: Use in service constructors or repositories to lazy-load Eloquent relationships or external services:

public function __construct() {
    $this->lazyPosts = lazy(fn() => Post::all());
}

Implementation Patterns

1. Lazy Initialization in Services

Replace eager loading with deferred objects in Laravel services:

class UserService {
    private Deferred<User> $user;

    public function __construct() {
        $this->user = lazy(fn() => User::find(1));
    }

    public function getPosts(): Collection {
        return $this->user->get()->posts; // Loads only when called
    }
}

2. Proxy Syntax for Cleaner Code

Leverage __get()/__call() to avoid .get() boilerplate:

// Instead of:
$deferredUser->get()->name;

// Use:
$deferredUser->name; // Proxy syntax (requires type hints)

3. Type Safety with Generics

Annotate deferred objects for IDE autocompletion and static analysis:

/** @var Deferred<User> */
private $user;

public function __construct() {
    $this->user = lazy(fn() => User::find(1));
}

// PhpStorm will autocomplete `->name`, `->email`, etc.

4. Eager Evaluation for Cached Data

Use now() to wrap preloaded data (e.g., from Redis or cache):

$cachedUser = now(Cache::get('user:1'));
$cachedUser->posts; // No generator overhead

5. Integration with Laravel Jobs

Defer job creation until needed (avoid instantiating jobs prematurely):

class SendWelcomeEmailJob implements ShouldQueue {
    public function __construct(private Deferred<User> $user) {}
}

$user = later(fn() => User::find(1));
SendWelcomeEmailJob::dispatch($user);

6. Testing with Mocks

Replace generators with arrays for predictable test data:

// Test
$this->lazyUser = lazy([new User(['name' => 'Test'])]);
$this->assertEquals('Test', $this->lazyUser->get()->name);

// Or mock the Deferred interface:
$mock = $this->createMock(Deferred::class);
$mock->method('get')->willReturn(new User());

Gotchas and Tips

Pitfalls

  1. Generator Reuse:

    • Generators must not be reused after failure. If a generator throws an exception, subsequent calls to get() will fail. Reset the generator or use now() for stateless results.
    • Fix: Wrap generators in error handling:
      $deferred = later(function () {
          try {
              yield User::find(1);
          } catch (Exception $e) {
              yield null; // Fallback
          }
      });
      
  2. Proxy Syntax Limitations:

    • Proxy methods ($deferred->method()) only work for public properties/methods of the underlying object.
    • Fix: Use .get()->method() for private/protected members.
  3. PHP 8.2+ Requirement:

    • The package drops support for PHP <8.2 (as of v0.1.6). Ensure your Laravel app uses PHP ≥8.2.
  4. No Async by Default:

    • later() does not run in a separate thread/process. It defers execution to the next microtask (e.g., after the current script finishes).
    • Workaround for CLI: Use later()->delay() with a small timeout to simulate async:
      later()->delay(fn() => $this->process(), 0.1); // Runs after current script yields
      
  5. Type Hints in PHP 8.0:

    • Generics (Deferred<User>) require PHP 8.0+. For older versions, use @var annotations.

Debugging Tips

  • Check Generator State: Use iterator_to_array($deferred->getGenerator()) to inspect yielded values during debugging.
  • Force Evaluation: Call .get() early to catch exceptions before they propagate:
    try {
        $user = $deferredUser->get();
    } catch (Exception $e) {
        Log::error("Deferred failed: " . $e->getMessage());
        $user = null;
    }
    
  • Memory Leaks: Generators hold references to their closure scope. Avoid capturing large objects (e.g., entire Eloquent models) in closures. Prefer IDs or minimal data.

Extension Points

  1. Custom Adapters: Extend Later\Interfaces\Deferred to integrate with Laravel’s queue system:
    class QueueDeferred implements Deferred {
        public function get() {
            return Queue::laterOn('default', now(), fn() => $this->resolve());
        }
    }
    
  2. Retry Logic: Wrap get() in a retry helper for transient failures:
    $deferred = later(fn() => Api::call());
    $result = retry(3, fn() => $deferred->get());
    
  3. Caching Layer: Cache deferred results using Laravel’s cache:
    $deferred = later(fn() => Cache::remember('user:1', 60, fn() => User::find(1)));
    

Laravel-Specific Quirks

  • Request Lifecycle: Deferred objects won’t persist across HTTP requests. Reset them in each request (e.g., via middleware or service containers).
  • Queue Integration: To defer jobs to Laravel’s queue, combine with later() and dispatch():
    later()->delay(fn() => SendEmailJob::dispatch($user), 5); // Runs in 5 seconds via queue
    
  • Artisan Commands: Useful for batch processing (e.g., staggering API calls):
    later()->delay(fn() => $this->processBatch($batch), 2); // 2-second delay between batches
    
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.
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
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata