- What is sanmai/later and what problem does it solve in a Laravel app?
- sanmai/later is a fully-typed PHP library for lazy evaluation using generators. It returns a Deferred object whose get() method computes a value on first use and reuses it afterward, so expensive object construction can be deferred until a code path actually needs it. In Laravel it fits cases such as heavy API clients, large DTOs, tenant context, or aggregates that are often never read.
- How do I install sanmai/later in Laravel?
- Install it with composer require sanmai/later. There is no service provider, config file, facade, container binding, or published asset to register. You use the namespaced functions directly in your own classes and services.
- Does sanmai/later work with Laravel 10, 11, and 12?
- Yes, the package is framework-agnostic and does not touch Laravel's boot sequence, so it can be dropped into Laravel 10, 11, or 12 according to the technical assessment. It is a plain Composer dependency rather than a Laravel package with framework-specific integration. Confirm your PHP version against the tagged release before adoption.
- Which PHP versions does sanmai/later support, and is it stable?
- The technical assessment states release 0.1.6 dropped PHP below 8.2, while the README excerpt says the latest version requires PHP 7.4 or greater, so verify the tag you install. The project is pre-1.0 with a single maintainer, no dependents, and no Semver API stability guarantee. Confirm your fleet's PHP floor and pin an appropriate tagged release.
- What is the difference between later(), lazy(), and now()?
- later(callable) wraps a generator function, lazy(iterable) wraps a generator or iterable, and now(value) wraps a value you already have. All three return a Deferred<T> with the same get() call site, so production and test paths do not need to branch. This is useful when a cache hit or test fixture is already available but you want the same Deferred interface.
- How does Deferred get() memoization work?
- The first get() call computes the value by consuming the generator, and every later get() call returns the same instance. PHP guarantees a generator is consumed exactly once, so the library gets single-evaluation semantics without defensive flags or callbacks. The memoization is per Deferred object, not global.
- Can sanmai/later handle delays, retries, debounce, throttling, or background jobs?
- No. sanmai/later is a memoized lazy-value wrapper, not a scheduler, queue, or async runtime. It does not provide delay(), debounce(), throttle(), timeout(), retries, or afterResponse() despite some third-party summaries claiming otherwise. Use Laravel's queue and defer() primitives for delayed or background work.
- Can I serialize a Deferred object or put it in a queued job payload?
- No. Deferred values are not serializable because generator state cannot cross a queue or cache boundary. A Deferred accidentally placed in a queued job payload is a runtime failure. Resolve the value with get() before crossing a queue, cache, or serialization boundary.
- Is sanmai/later safe with Laravel Octane or long-lived workers?
- Memoization is per Deferred object, so a Deferred held in a singleton can leak stale values across requests under Octane or any long-lived worker. Keep Deferred instances scoped to the request or service lifecycle that owns them. Do not store request-specific lazy values in application singletons.
- How should I type Deferred properties for PHPStan, Psalm, and tests?
- The package is fully typed and documented for PHPStan, Psalm, and Phan templates, but its magic __call and __get forwarding to get() can defeat static analysis. Put a Deferred<T> docblock on every property so typos and wrong types are caught early. In tests, use now(value) when the value is already available so call sites keep the same Deferred interface.