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

Promise Laravel Package

internal/promise

Lightweight Promises/A implementation for PHP (fork of reactphp/promise). PHP 8.1+ compatible with strict types and improved type annotations. Drop-in replacement for react/promise v2/v3 with reusable rejection handling and safer defaults.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require internal/promise
    

    Ensure your project uses PHP 8.1+ (required for full compatibility).

  2. First Use Case: Replace a synchronous callback with a Promise for an async HTTP request (e.g., using Guzzle):

    use Internal\Promise\Promise;
    use GuzzleHttp\Client;
    
    $client = new Client();
    $promise = Promise\resolve()
        ->then(function () use ($client) {
            return $client->requestAsync('GET', 'https://api.example.com/data');
        })
        ->then(function ($response) {
            return json_decode($response->getBody(), true);
        });
    
    $promise->then(function ($data) {
        // Handle resolved data
    })->catch(function (\Throwable $e) {
        // Handle rejection
    });
    
  3. Key Entry Points:

    • Promise\resolve($value): Create a resolved promise.
    • Promise\reject($reason): Create a rejected promise.
    • Deferred: For manual promise control (e.g., async operations).
    • Promise\all([$promise1, $promise2]): Run promises in parallel.
    • Promise\race([$promise1, $promise2]): Return the first settled promise.
  4. Where to Look First:

    • Documentation: Covers core concepts (e.g., then/catch/finally).
    • API Reference: Ported from when.js; details methods like cancel().
    • Tests: Run composer test to see real-world usage patterns.

Implementation Patterns

Core Workflows

1. Async Database Queries

Use Deferred to wrap Eloquent queries or raw PDO calls:

use Internal\Promise\Deferred;
use Illuminate\Support\Facades\DB;

$deferred = new Deferred();
DB::connection()->getPdo()->queryAsync('SELECT * FROM users', function ($result) use ($deferred) {
    $deferred->resolve($result->fetchAll());
});
$promise = $deferred->promise();

$promise->then(function ($users) {
    // Process users
});

2. Parallel API Calls

Combine Promise\all() with Laravel HTTP clients:

use Illuminate\Support\Facades\Http;
use Internal\Promise\Promise;

$promises = [
    Promise\resolve()->then(fn() => Http::get('https://api1.example.com/data')),
    Promise\resolve()->then(fn() => Http::get('https://api2.example.com/data')),
];
Promise\all($promises)->then(function ($responses) {
    // Merge responses
});

3. Error Handling

  • Global Unhandled Rejections: Set a custom handler:
    Promise\set_rejection_handler(function (\Throwable $e) {
        \Log::error('Unhandled promise rejection', ['exception' => $e]);
    });
    
  • Per-Promise: Use catch():
    $promise->catch(function (\Throwable $e) {
        \Toast::error("Failed to load data: " . $e->getMessage());
    });
    

4. Cancellation

Cancel long-running promises (e.g., timeouts):

$promise = Promise\resolve()->then(fn() => sleep(5));
$promise->cancel(); // Stops execution if supported by the underlying operation.

5. Chaining with Laravel

Integrate with Laravel’s Bus or Queue:

use Illuminate\Bus\Queueable;
use Internal\Promise\Promise;

class ProcessOrder implements Queueable
{
    public function handle()
    {
        return Promise\resolve()
            ->then(fn() => $this->validateOrder())
            ->then(fn() => $this->shipOrder())
            ->finally(fn() => \Log::info('Order processed'));
    }
}

Integration Tips

  • Avoid Blocking: Never call ->wait() in synchronous contexts (e.g., route handlers). Use then() for async continuation.
  • Type Safety: Leverage PHP 8.4’s union types with resolve(T $value):
    $promise = Promise\resolve<string>('data');
    
  • Laravel Service Providers: Bind Deferred or Promise to the container for dependency injection:
    $this->app->bind(Deferred::class, fn() => new Deferred());
    

Gotchas and Tips

Pitfalls

  1. No Implicit await: Unlike JavaScript, PHP lacks await syntax. Use then() chains or libraries like Amp for coroutines.

    // ❌ Avoid this in PHP (pseudo-code):
    // $data = await $promise;
    
    // ✅ Correct:
    $promise->then(fn($data) => /* ... */);
    
  2. Rejection Handling:

    • Unhandled Rejections: By default, unhandled rejections log to error_log(). Override with set_rejection_handler().
    • Silent Failures: Always chain catch() to avoid silent promise failures.
  3. PHP 8.1+ Strict Types:

    • resolve() Requires a Value: Use null for no value:
      Promise\resolve(null); // Valid
      Promise\resolve();     // ❌ TypeError
      
    • reject() Requires Throwable: Never pass strings or objects:
      Promise\reject(new \RuntimeException('Error')); // ✅
      Promise\reject('Error'); // ❌ TypeError
      
  4. Cancellation Limitations:

    • Not all operations support cancellation (e.g., sleep()). Use timeouts or manual checks:
      $promise = Promise\resolve()->then(fn() => sleep(10));
      $promise->cancel(); // May not work; use a timeout instead.
      
  5. Global State:

    • Rejection Handler: Only one global handler is active. Overwriting it replaces the previous one:
      Promise\set_rejection_handler(fn() => /* ... */);
      

Debugging

  1. Inspect Promises: Use Promise\is_pending(), is_rejected(), or is_fulfilled() to debug state:

    if (Promise\is_pending($promise)) {
        \Log::debug('Promise still pending');
    }
    
  2. Stack Traces: Enable E_ALL and check error_log() for unhandled rejections. For custom logging:

    Promise\set_rejection_handler(function (\Throwable $e) {
        \Sentry\captureException($e);
    });
    
  3. Memory Leaks:

    • Unbound Promises: Ensure promises are resolved/rejected to free resources. Use finally() for cleanup:
      $promise->finally(fn() => $resource->close());
      

Extension Points

  1. Custom Promise Classes: Extend PromiseInterface for domain-specific logic (though classes are final, use composition):

    class ApiPromise implements PromiseInterface
    {
        private PromiseInterface $promise;
    
        public function __construct(PromiseInterface $promise)
        {
            $this->promise = $promise;
        }
    
        public function then(callable $onFulfilled): PromiseInterface
        {
            return $this->promise->then($onFulfilled);
        }
    
        // Implement other PromiseInterface methods...
    }
    
  2. Async Laravel Helpers: Create a facade for common patterns:

    use Illuminate\Support\Facades\Facade;
    
    class PromiseFacade extends Facade
    {
        protected static function getFacadeAccessor() { return 'promise'; }
    }
    

    Register in AppServiceProvider:

    $this->app->singleton('promise', fn() => new PromiseHelper());
    
  3. Testing: Use Promise\resolve()/reject() in tests to mock async behavior:

    $this->expectException(\RuntimeException::class);
    Promise\reject(new \RuntimeException('Test error'))->wait();
    

Performance Tips

  1. Avoid wait(): Blocking calls (e.g., in tests) can hang the event loop. Use then() or Promise\all() instead.

  2. Reuse Deferreds: Reuse Deferred instances for multiple operations to reduce overhead:

    $deferred = new Deferred();
    $promise1 = $deferred->promise();
    $promise2 = $deferred->promise(); // Shares the same resolution path.
    
  3. Parallelism: Use `Promise

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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
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