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.
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:
later() – Wrap a generator function.lazy() – Convert an existing iterable (e.g., array) into a deferred object.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());
}
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
}
}
Leverage __get()/__call() to avoid .get() boilerplate:
// Instead of:
$deferredUser->get()->name;
// Use:
$deferredUser->name; // Proxy syntax (requires type hints)
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.
Use now() to wrap preloaded data (e.g., from Redis or cache):
$cachedUser = now(Cache::get('user:1'));
$cachedUser->posts; // No generator overhead
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);
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());
Generator Reuse:
get() will fail. Reset the generator or use now() for stateless results.$deferred = later(function () {
try {
yield User::find(1);
} catch (Exception $e) {
yield null; // Fallback
}
});
Proxy Syntax Limitations:
$deferred->method()) only work for public properties/methods of the underlying object..get()->method() for private/protected members.PHP 8.2+ Requirement:
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).later()->delay() with a small timeout to simulate async:
later()->delay(fn() => $this->process(), 0.1); // Runs after current script yields
Type Hints in PHP 8.0:
Deferred<User>) require PHP 8.0+. For older versions, use @var annotations.iterator_to_array($deferred->getGenerator()) to inspect yielded values during debugging..get() early to catch exceptions before they propagate:
try {
$user = $deferredUser->get();
} catch (Exception $e) {
Log::error("Deferred failed: " . $e->getMessage());
$user = null;
}
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());
}
}
get() in a retry helper for transient failures:
$deferred = later(fn() => Api::call());
$result = retry(3, fn() => $deferred->get());
$deferred = later(fn() => Cache::remember('user:1', 60, fn() => User::find(1)));
later() and dispatch():
later()->delay(fn() => SendEmailJob::dispatch($user), 5); // Runs in 5 seconds via queue
later()->delay(fn() => $this->processBatch($batch), 2); // 2-second delay between batches
How can I help you explore Laravel packages today?