Search by

Reference implementations for Front-Interop.

Package info

github.com/front-interop/impl

pkg:composer/front-interop/impl

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

1.0.0-beta2 2026-09-02 15:02 UTC

This package is auto-updated.

Last update: 2026-10-07 20:52:18 UTC


README

PDS Skeleton PDS Composer Script Names

Reference implementations of the Front-Interop interface for PHP 8.4+.

These implementations are intentionally naive; they exist to showcase the FrontController contract itself. Production front controllers would be obtained from an IOC container and would compose a request/response system, a router/dispatcher, and so on.

Installation

composer require front-interop/impl

Usage

Three reference implementations cover three execution contexts.

ConsoleFrontController

A command-line front controller, reading $argv and writing to $stdout and $stderr. Both streams are optional; they default to php://stdout and php://stderr.

use FrontInterop\Impl\ConsoleFrontController;

$front = new ConsoleFrontController($argv);
exit($front->run());

That is bin/hello.php, apart from the autoloader. Run it with:

php bin/hello.php World

RequestFrontController

An HTTP front controller, reading an injected query array and writing HTML to $output. That stream is optional; it defaults to php://output.

use FrontInterop\Impl\RequestFrontController;

$front = new RequestFrontController($_GET);
exit($front->run());

That is public/index.php, apart from the autoloader. Run composer hello at the package root, then visit:

http://localhost:8080/index.php?name=World

FrankenFrontController

A front controller for FrankenPHP, wrapping a RequestFrontController in a frankenphp_handle_request() worker loop.

use FrontInterop\Impl\FrankenFrontController;

$front = new FrankenFrontController(100);
exit($front->run());

It runs only under the FrankenPHP binary in worker mode, because frankenphp_handle_request() does not exist elsewhere.

Classes

Interface Implementation
FrontController ConsoleFrontController, RequestFrontController, FrankenFrontController

All classes are in the FrontInterop\Impl namespace. The three concrete classes extend AFrontController for the helpers they share.

Conformance

Three of the Front-Interop directives for run() shape these implementations:

  • return a status between 0 and 254
  • do not end run() by calling exit() or die()
  • do not let a Throwable escape

Returning a status

ConsoleFrontController returns 1 when no name is given and 0 once it has written its greeting.

RequestFrontController returns 0 after emitting its page, and 1 from error(). A 0 does not mean that nothing went wrong: it returns 0 with a 422 when no name is given, because the request was handled and a response was emitted. That counts as success in an HTTP context.

FrankenFrontController returns the status from the last request handled, set only by RequestFrontController::run(). It returns 0 if the runtime ends the loop before any request is handled.

The error() method in every controller returns 1.

Not calling exit()

None of the implementations call exit() or die(). The scripts that start them do: bin/hello.php and public/index.php both end with exit($front->run()). The script receives the status and decides what to do with it.

FrankenFrontController bounds its worker loop with $requestMax so that run() returns after that many requests. A 0 maximum defers the decision to the runtime. The loop ends when the runtime returns false.

Not letting a Throwable escape

Each implementation of run() wraps its work in a try/catch block. The catch sends the Throwable to caught(), which reports through error() and then releases the Throwable. (The release is guarded because the destructor runs at that moment, and a throw there would reach the caller after run() had already computed its status.)

Each error() implementation guards its own writes too. A stream can be closed, or open and refuse the write, and a throw from error() would escape run().

ConsoleFrontController writes to stderr and falls back to log() only when that write fails. It tests what fwrite() returns, because a stream that refuses the write reports false rather than throwing.

RequestFrontController always logs, then attempts the response separately, so a failed log does not prevent the 500. FrankenFrontController logs and returns 1.

The directives bind run() alone. ConsoleFrontController and RequestFrontController throw InvalidArgumentException from __construct() when a stream argument is not a stream resource. Construction is outside them.

Testing

composer test runs the suite. Most tests need nothing beyond PHP.

Two tests in FrankenServerTest start a real frankenphp binary in worker mode and send it HTTP requests. They look for the binary on the PATH, or at the path in the FRANKENPHP_BIN environment variable, and skip when they find none. They also skip on Windows. Set REQUIRE_FRANKENPHP=1 to make a missing binary a failure; CI sets it on Ubuntu with PHP 8.4. On macOS, brew install dunglas/frankenphp/frankenphp installs the binary.

See the Front-Interop interface package for the full specification.