Skip to content

Repository files navigation

oxphp/runtime

OxPHP runtime adapter — run Symfony, Laravel and PSR-15 applications on the OxPHP server in both traditional and worker mode.

Extends symfony/runtime. Zero hard dependencies on any framework or PSR-7 implementation — everything is auto-detected when the container is resolved.

Requirements

  • PHP 8.4+
  • OxPHP server (for production use; the runtime transparently falls back to symfony/runtime defaults when not running under the OxPHP SAPI)
  • symfony/runtime ^6.4 || ^7.0

Installation

composer require oxphp/runtime

Then set the runtime in .env:

APP_RUNTIME=OxPHP\Runtime\Runtime

Your public/index.php stays as it would be under symfony/runtime:

<?php
use App\Kernel;

require_once \dirname(__DIR__).'/vendor/autoload_runtime.php';

return fn(array $context) => new Kernel($context['APP_ENV'], (bool)$context['APP_DEBUG']);

Supported application types

Return type from index.php Runner
Psr\Http\Server\RequestHandlerInterface Psr15Runner
Illuminate\Contracts\Http\Kernel LaravelRunner
Symfony\Component\HttpKernel\HttpKernelInterface HttpKernelRunner
Symfony\Component\HttpFoundation\Response HttpFoundationResponseRunner
Psr\Http\Message\ResponseInterface Psr7ResponseRunner

Any other type throws LogicException. Console applications are out of scope — run them under the stock PHP CLI SAPI.

Traditional vs worker mode

Mode is auto-detected via oxphp_is_worker(). Nothing to configure on the runtime side. In worker mode:

  • Your application boots once per worker thread.
  • oxphp_worker() drives the loop internally; the runtime wraps each request in try/catch(\Throwable) so a broken handler cannot poison the worker.
  • Between requests, OxPHP performs a soft reset (output buffers, headers, superglobals). Framework-specific state you want to reset on top of that goes through the resetter chain.

Resetters

Register custom resetters via APP_RUNTIME_OPTIONS:

APP_RUNTIME_OPTIONS="{\"resetters\":[\"App\\\\Runtime\\\\EntityManagerResetter\"]}"

Your class implements OxPHP\Runtime\Resetter\ResetterInterface:

use OxPHP\Runtime\Resetter\ResetterInterface;

final class EntityManagerResetter implements ResetterInterface
{
    public function __construct(private readonly EntityManagerInterface $em) {}

    public function reset(): void
    {
        $this->em->clear();
    }
}

Symfony users get the container's services_resetter (any service tagged kernel.reset) wired up automatically — no registration needed.

PSR-17 factory

Used only by PSR-15 and bare PSR-7 Response paths. Auto-detected in this order:

  1. Nyholm\Psr7\Factory\Psr17Factory (recommended)
  2. GuzzleHttp\Psr7\HttpFactory
  3. HttpSoft\Message\ServerRequestFactory (+ siblings)
  4. Laminas\Diactoros\ServerRequestFactory (+ siblings)

Override via APP_RUNTIME_OPTIONS:

APP_RUNTIME_OPTIONS="{\"psr17_factory\":\"My\\\\Factory\"}"

Streaming

StreamedResponse, StreamedJsonResponse, and PSR-7 bodies with readable streams are streamed chunk-by-chunk — ideal for SSE and large payloads.

Streamed callbacks are driven live: every echo inside a StreamedResponse callback goes to the wire as soon as it happens — chunks are never collected and replayed after the callback returns. The runtime enables PHP's implicit flush while driving the callback, so the engine pushes each chunk through the OxPHP SAPI's flush hook on write; the callback does not need to call flush() itself. PSR-7 stream bodies are flushed per chunk via oxphp_stream_flush(). An exception thrown mid-stream closes the runtime's output buffers cleanly (bytes already streamed stay sent, partial buffers are discarded) and never poisons the worker.

For "respond early, keep working" patterns use oxphp_finish_request() directly in your controller:

$response = new JsonResponse(['status' => 'accepted']);
// ... after sending ...
\oxphp_finish_request();
// background work continues; the client already got the response

License

MIT

About

Symfony Runtime adapter for the OxPHP server. Run Symfony, Laravel and PSR-15 applications in traditional or worker mode without changing your index.php. Auto-detects PSR-17 factories, supports streaming responses, and exposes a small resetter API for per-request worker state cleanup.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages