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

Engine Laravel Package

psx/engine

A lightweight engine component for the PSX PHP framework, providing core runtime and request-handling abstractions for building API-driven applications. Integrates seamlessly with other psx packages.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and orient yourself

composer require psx/engine

Then read, in this order:

  1. vendor/psx/engine/README.md — usually a one-paragraph description plus a bootstrap snippet.
  2. vendor/psx/engine/src/ — the engine interface plus one adapter class per supported server type (FPM/Apache, Swoole, ReactPHP, Workerman, RoadRunner-style workers). The directory listing is the feature matrix; there is no separate docs site.
  3. vendor/psx/engine/tests/ — the closest thing to usage examples. Copy the bootstrap from the test that matches your target runtime.

The mental model: the package is a thin translation layer between a server runtime and your PSR-7/PSR-15 application. An engine receives a ServerRequestInterface, hands it to your request handler, and writes the resulting ResponseInterface back out. Your application code should not know which engine it is running under.

First use case — keep PHP-FPM as the production baseline and add a worker engine behind a flag, so you can benchmark before committing:

// public/index.php  (FPM path, unchanged)
$kernel = require __DIR__ . '/../bootstrap/kernel.php';
$response = $kernel->handle(ServerRequestFactory::fromGlobals());
(new SapiEmitter())->emit($response);
// bin/server.php  (worker path)
$kernel = require __DIR__ . '/../bootstrap/kernel.php';
$engine = new \PSX\Engine\Swoole($kernel, ['host' => '0.0.0.0', 'port' => 8080]);
$engine->run();   // exact method name depends on the adapter — check src/

If those two files share the same $kernel, you have already validated the abstraction.

Implementation Patterns

One kernel, many thin entry points. Do not put business logic in the engine script. Structure as:

  • bootstrap/kernel.php — builds the container, router, middleware stack, returns a PSR-15 RequestHandlerInterface.
  • public/index.php — FPM entry point, builds a request from globals, emits.
  • bin/server.php — worker entry point, builds the engine around the same kernel.

Engine selection by configuration, not by branching in application code. A small factory keyed off an env var (APP_ENGINE=fpm|swoole|reactphp) keeps Docker images identical across environments and lets CI run the same suite against multiple runtimes.

Boot once, handle many. Anything expensive — container compilation, route cache warmup, metadata/annotation parsing, config loading — belongs in the bootstrap, above the engine construction. This is the entire performance argument for using the package; if you lazy-load per request anyway you gain nothing.

Request-scoped state goes in request attributes. In FPM you can get away with a singleton holding "the current user". In a worker that singleton survives across requests. Pass identity, tenant, correlation IDs, and locale through $request->withAttribute(...) and read them from the request, never from the container.

Keep the full middleware stack PSR-15. Because the engine only speaks PSR-7/PSR-15, everything you build — auth, CORS, error handling, request logging — stays portable between the FPM and worker paths. This is the package's main day-to-day value.

Error handling as middleware, not as a global handler. Register an outermost middleware that catches Throwable, logs with the correlation ID, and returns a 500 response. Do not rely on set_exception_handler; in worker mode an uncaught error can take down the process rather than the request.

Deployment integration. Dockerfile with a shared base and two cmd variants; a /health route that returns 200 without touching the database; readiness checks that verify the worker is listening on its port rather than just that the container is up. For supervised workers, configure graceful shutdown (SIGTERM → stop accepting, drain in-flight, exit) and a max-requests recycle setting to bound memory growth.

Test parity. Run your functional suite twice in CI: once against an in-process FPM-style request, once against a spawned worker. The second run catches the shared-state bugs the first one cannot.

Gotchas and Tips

Superglobals are stale or empty. In worker mode $_SERVER, $_GET, $_POST, and $_FILES are whatever they were when the process booted. Any legacy code reading them directly will silently return wrong data. Grep for $_ in application code before adopting a worker engine; this is the single most common migration failure.

header(), setcookie(), echo, and output buffering do nothing useful. All output must go through the returned ResponseInterface. Framework code or third-party libraries that echo will either be swallowed or corrupt the wire format depending on the adapter.

exit and die kill the worker. Any library that calls them (some error handlers, some CLI helpers) turns one bad request into an outage. Convert to exceptions and let the error middleware handle them.

Memory grows monotonically unless you fight it. Watch for: container singletons accumulating entities, static caches in libraries, Monolog handlers buffering, Doctrine's EntityManager retaining the identity map, and event dispatchers accumulating listeners. Reset or recreate per request; measure RSS over a few thousand requests before declaring victory.

move_uploaded_file() and is_uploaded_file() fail. They check SAPI state that doesn't exist in worker mode. Read from the PSR-7 upload stream instead.

Sessions behave differently. Default PHP session handling assumes script-end write-and-close. Under a persistent worker the same session can be locked or reused across requests. Move to an explicit PSR-7 session middleware with a store you control.

Limits live in the engine, not php.ini. post_max_size, max_execution_time, memory_limit, keep-alive timeouts, and max body size are configured on the Swoole/ReactPHP/Workerman server object. Setting php.ini values and expecting them to apply is a frequent source of confusion.

Debugging: because errors may not surface in the HTTP response, always log inside the error middleware before returning. When a worker appears hung, check whether the process is blocked on a synchronous call (a blocking DB driver, file_get_contents on a URL, sleep) — the event loop will stall for everyone, not just that request.

Treat the API as unstable. With a very small user base and no dependents, class names and constructor signatures can change between minor versions. Pin an exact version in composer.json, keep your engine bootstrap to a handful of lines, and retain the FPM entry point as a fallback so a broken adapter is a config change rather than a rollback.

Extension points: the engine interface itself (write your own adapter for an unsupported runtime), the response emitter (override for streaming or large file responses), and the middleware stack (the portable place to put anything you might later need to run under a different engine).

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin