Weave 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

Util Laravel Package

swlib/util

swlib/util is a lightweight PHP utility package for Laravel and standalone projects, offering reusable helpers that reduce boilerplate and simplify common development tasks. Its simple API makes it easy to drop in and keep code clean, consistent, and readable.

Deep Wiki
Context7

Getting Started

swlib/util is a small utility belt that sits on top of the Swoole extension. It does not replace Swoole — it wraps the rough edges of coroutines, wait groups, process handling, and shared context so that ordinary PHP code (including Laravel code you’re porting into a Swoole worker) can be written without touching Swoole\Coroutine\* directly.

Minimal steps:

composer require swlib/util:^1.0
php -m | grep -i swoole      # must show "swoole"
php -r 'echo SWOOLE_VERSION, PHP_EOL;'

Requirements to check before anything else:

Requirement Why it matters
ext-swoole >= 4.4 (ideally 4.8+) The library predates Swoole 5; several coroutine APIs were deprecated/renamed
PHP 7.2–7.4 Last release 2020-08-26; PHP 8 support is not guaranteed
CLI-only usage These utilities assume Swoole\Runtime::enableCoroutine() and a running Swoole server/process

Where to look first: open vendor/swlib/util/src/ and read the class list. The package is tiny (a handful of files), there is no documentation site worth trusting, and the test suite is thin — the source is the documentation. Read the constructor signatures of the wait-group/coroutine/process classes before designing around them.

The first use case you will hit in real life is fan-out I/O inside a Swoole worker: you have 30 independent HTTP/DB calls that currently run sequentially and you want them concurrent without leaking coroutines. A wait-group primitive is exactly the right tool:

use Swlib\Util\WaitGroup;
use Swoole\Coroutine;

$wg = new WaitGroup();

foreach ($userIds as $id) {
    $wg->add();
    Coroutine::create(function () use ($wg, $id) {
        try {
            $profile[$id] = fetchProfile($id); // hooked I/O
        } finally {
            $wg->done();                       // always done, even on throw
        }
    });
}

$wg->wait();

If that compiles and returns in roughly the time of the slowest call rather than the sum of all calls, you have validated the package end-to-end.

Implementation Patterns

1. Fan-out / fan-in with a WaitGroup. The canonical pattern above. Always pair add() with a finally { done(); }; a single uncaught exception without done() deadlocks the whole worker on wait(). Keep the $wg object scoped to a request/job, never in a static property.

2. Bounded concurrency with a channel as a semaphore. Unbounded Coroutine::create in a loop will exhaust the worker pool or the remote service. Throttle explicitly:

$limit = new \Swoole\Coroutine\Channel(16);

foreach ($urls as $url) {
    $limit->push(true);                        // blocks at 16
    \Swoole\Coroutine::create(function () use ($limit, $url, &$out) {
        try { $out[$url] = httpGet($url); }
        finally { $limit->pop(); }
    });
}

The utility package does not give you a scheduler — this is still your job.

3. Wrap coroutine spawns in one place. Don’t scatter Coroutine::create across controllers and jobs. Put a small CoroutineRunner service in Laravel’s container, have it own the wait group and the semaphore, and let callers hand it callables. When Swoole’s API shifts (and it does), you change one file.

4. Process helpers for CPU-bound work. If a utility process class is present in src/, use it for tasks that would block the event loop (image resizing, PDF generation, large JSON transforms) rather than wrapping them in coroutines. Coroutines cooperate; they don’t preempt. A for loop over 10M rows inside a coroutine stalls the entire worker just as badly as in fpm.

5. Context propagation. Per-coroutine context is the single most valuable utility in this family: correlation IDs, tenant IDs, current user, trace spans. Set it at the entry point of a request/job, read it in the depths of your service layer, and make sure any helper you write (logger processors, DB query listeners) reads from it rather than from $_SERVER or a request singleton.

6. Integration with Laravel. There is no service provider. Register the bindings yourself in an app-level provider, and make sure the provider is only loaded in the Swoole/Octane-style entrypoint so the package never gets pulled into fpm requests where Swoole\Coroutine is unavailable.

7. Testing. Unit-test pure logic in normal PHPUnit. For anything asserting on coroutine behaviour, run the test suite inside Swoole\Coroutine\run(fn() => ...) or inside a test server process; a plain phpunit invocation will throw "API must be called in the coroutine" and you’ll waste an afternoon.

Gotchas and Tips

  • The package is effectively unmaintained. Last release 2020-08-26, ~10 stars. Treat it as vendored source you own, not as a dependency you upgrade. Pin the exact version in composer.json and consider copying the one or two classes you actually use into app/Support/.
  • Swoole 5 incompatibilities are likely. Coroutine::getuid() is deprecated in favour of getCid(), Swoole\Runtime::enableCoroutine() semantics changed, and several Channel/Coroutine behaviours were tightened. If a class blows up on Swoole 5, it’s usually a one-line rename — but you’ll be patching vendor code, so fork it.
  • wait() deadlocks silently. If any branch throws before done(), the worker hangs with no error. Wrap every unit of work in try/finally and add a defer-style helper; also set a channel timeout on your semaphore so a stuck coroutine surfaces as an exception instead of a frozen process.
  • Exceptions inside coroutines are swallowed or re-thrown at odd times. Collect failures into an array passed by reference, or push them into a channel, then decide policy after wait(). Don’t rely on the outer try/catch to see them.
  • Blocking calls still block the whole worker. Native MySQL via PDO is fine only when runtime hooks are enabled; shell_exec, sleep (non-hooked), and heavy CPU loops are not. Audit for them before blaming the library.
  • State leaks between requests. Anything held in a static property or a long-lived channel survives request boundaries in a Swoole server. Reset context and clear wait groups in a finally at the worker request boundary.
  • Channel capacity is not a rate limit. A size-16 channel limits in-flight coroutines, not requests per second against a downstream API. Add a token bucket on top if the remote service cares.
  • Don’t mix this with its siblings blindly. swlib/saber and swlib/http-client are from the same era and have the same maintenance profile; if you adopt one, adopt them all at pinned versions, or prefer a modern client.
  • Extension point: the useful escape hatch is composition, not inheritance — wrap the helpers in your own thin service classes so a future replacement (native Swoole\Coroutine\WaitGroup, or Octane’s concurrency facade) is a swap, not a rewrite.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package