Mini Framework

Designed for decades, not release cycles.

LLMs and senior developers: read MINI-STYLE.md before working on Mini projects.

composer require fubber/mini
mkdir _routes
echo '<?php return date("c");' > _routes/time.php
composer exec mini serve

Visit http://localhost/time - you're running.


Framework Aspects

Mini provides composable, well-implemented functionality for many concerns in modern application development. All features lazy-load—nothing is loaded until touched.

Core Infrastructure

  • Service Container: Mini::$mini is a PSR-11 container managing service lifetimes (Singleton, Scoped, Transient), application phases, and dependency resolution. Access services via helper functions like db(), cache(), auth().

  • Dispatcher: Bootstraps PSR-7 requests from HTTP globals, routes requests, converts exceptions to responses, and emits PSR-7 responses. Entry point: mini\dispatch().

  • Router: File-based routing where paths map directly to _routes/ files. Supports wildcards (_.php), dynamic segments, controller mounting via __DEFAULT__.php, and PSR-15 handler integration. For pattern based routing, combine file based routing with Controllers.

  • Http: PSR-7 compliant request/response objects, HTTP exceptions, and customizable error pages. Mini also supports native PHP output (echo, header()) alongside PSR-7.

  • Session: Transparent session management that replaces $_SESSION with a fiber-safe proxy. Auto-starts on access, integrates with async runtimes.

Security

  • Auth: Authentication facade where applications implement AuthInterface to define their auth scheme (sessions, JWT, API keys). Mini provides auth() for checking authentication, roles, and permissions.

  • Authorizer: Resource-based authorization answering "can this user do X to Y?" Check with can(Ability::Delete, $post) at collection, instance, or field level. Handlers resolve by type specificity.

Data Access

  • Database: PDO-backed database abstraction with db() for queries, transactions, and an immutable query builder (PartialQuery). Zero-config SQLite by default, environment-based MySQL/PostgreSQL configuration. Mini also provides a composable SQL 2003 query evaluator (INSERT, UPDATE, CREATE, DELETE with subqueries and joins and CTEs) in VirtualDatabase with predicate pushdown which can facilitate safe SQL access via APIs or be used internally as backends for entities. You can mount any PartialQuery as a table in a virtual table, and this works from real database backends and other virtual databases.

  • Table: Composable query builder for tabular data sources (arrays, CSV, JSON, database results) with a unified fluent API for filtering, sorting, and joining.

  • Cache: Zero-configuration PSR-16 caching that auto-selects the best driver (APCu → SQLite → Filesystem). Supports namespaced isolation and custom backends.

Web & API

  • Controller: Attribute-based routing with #[GET], #[POST], etc. Type-safe URL parameters, automatic return value conversion (arrays → JSON), and PSR-15 compatibility.

  • Template: Pure PHP templates with multi-level inheritance via $this->extend() and $this->block(). No template language to learn—just PHP.

  • Static: PSR-15 middleware serving static files from _static/ with HTTP caching, conditional requests (304), and multi-level path resolution.

  • Converter: Type conversion registry transforming return values, exceptions, and domain objects to HTTP responses. Resolves by type specificity with union type support.

Communication

  • Mail: RFC 5322-compliant email composition with MIME structure, HTML with inline images, attachments, and pluggable transports (mail, sendmail).

  • Logger: PSR-3 compatible logging with ICU MessageFormatter interpolation. Built-in handler writes to error_log; swap in Monolog or any PSR-3 logger.

Validation & Schema

  • Validator: JSON Schema-compatible validation with fluent API and attribute-based schemas. Composable, purpose-scoped (Create/Update), exportable to JSON Schema for client-side use.

  • Metadata: JSON Schema annotations for documenting classes via attributes—titles, descriptions, examples, UI hints—separate from validation rules.

Internationalization

  • I18n: Translation via t() using ICU MessageFormat (pluralization, gender, selects). File-per-source structure mirrors your code. Locale-aware formatting via fmt() for currency, dates, numbers.

Events & Extensibility

  • Hooks: Event dispatcher system with specialized patterns—Event (multi-fire), Trigger (one-time with memory), Handler (chain of responsibility), Filter (data pipeline), StateMachine.

Utilities

  • CLI: Argument parsing for command-line tools via ArgManager. Flags, options, subcommands, and delegation to external tools.

  • UUID: UUID generation with time-ordered v7 (database-friendly) as default, v4 for maximum randomness. ~200k UUIDs/second.

  • Async: Interface for async runtimes (phasync, Swoole, ReactPHP) to integrate with Mini's fiber-aware architecture.

  • Inference: Service interface for LLM-based structured evaluation—send prompts, receive schema-compliant JSON responses.

  • Util: Foundation utilities—IdentityMap (weak-ref object tracking), InstanceStore (typed singletons), Path (cross-platform paths), PathsRegistry (priority-based file resolution), QueryParser (SQL-like filtering), MachineSalt (zero-config cryptographic salt), and arbitrary-precision math (Decimal, BigInt).

CLI Tools

Mini includes command-line tools via vendor/bin/mini:

  • mini serve: Development server with auto-reload
  • mini migrations: Migration runner with tracking, rollback, and make scaffolding
  • mini translations: Manage translation files—validate, add missing strings, add languages, remove orphans
  • mini docs: Browse PHP documentation for classes, functions, and namespaces
  • mini test: Run tests with pattern matching
  • mini db: Interactive SQL REPL for your database
  • mini vdb: VirtualDatabase shell for CSV/JSON data sources
  • mini benchmark: HTTP performance benchmarking

Philosophy

Mini is built on a Lindy perspective: if a pattern has worked for 40 years, it will likely work for 40 more. We reject patterns that trigger frequent redesign.

Use PHP's engine, not userland abstractions. Traditional frameworks reinvent locale handling, date formatting, routing, and templating in PHP code. Mini uses PHP's C-level engine: intl extension for ICU, file system for routing, PHP files for templates.

Dependency locator, not dependency injection. DI in PHP forces proxy classes, scattered configuration, and compilation steps. We locate dependencies via db(), cache(), auth() - simple functions resolving from Mini::$mini. Same testability (swap the container service), no proxy explosion.

Embrace PHP's short-lived request cycle. PHP bootstraps fresh for each request - no memory leaks, no stale state, predictable cleanup. We optimize for this reality instead of fighting it.

Multiple routing paradigms. _routes/ files can echo output like classic PHP, return values (converted to PSR-7 via converter registry), return controllers with attribute-based routing, or return PSR-15 handlers (mount Slim, Mezzio, etc.). We don't reject patterns that have been idiomatic PHP for 20+ years.

Fiber-safe globals. $_GET, $_POST, $_COOKIE, $_SESSION are ArrayAccess proxies routing to the current PSR-7 request context - works in FPM, Swoole, ReactPHP, and Fiber-based async.

Full-stack, lazy-loaded. ORM, auth, i18n, templates, validation - all included, nothing loads until touched. Hello World uses ~300KB. Zero required dependencies enables mounting PSR-15 apps without dependency conflicts.

Engine-Native, Not Userland-Native

We use PHP's C-level engine, not userland reimplementations. Modern frameworks reimplement locale handling, date formatting, and number formatting in PHP code. Mini uses PHP's intl extension (ICU library in C) and native functions.

Engine-Level Performance

Internationalization:

// Mini: Use PHP's intl extension (C-level ICU)
\Locale::setDefault('de_DE');           // Sets locale for entire engine
echo fmt()->currency(19.99, 'EUR');     // "19,99 €" - formatted by ICU in C
echo t("Hello, {name}!", ['name' => 'World']);  // MessageFormatter in C

// Framework approach: Load massive translation arrays, parse ICU in PHP
$translator->trans('messages.welcome', ['name' => 'World'], 'en_US');

Routing:

// Mini: File system IS the routing table (OS-cached, instant lookup)
_routes/users/_.php  // Wildcard matches any ID, captured in $_GET[0]

// Framework approach: Parse regex routes on every request (slow)
$router->addRoute('GET', '/users/{id}', [UserController::class, 'show']);

Templates:

// Mini: PHP IS the template language (no parsing overhead)
<?= h($user->name) ?>  // Direct output buffering, closure-based inheritance

// Framework approach: Parse string templates into PHP (Blade, Twig)
{{ $user->name }}

What We Use (And Why)

Request/Response:

  • $_GET, $_POST, $_COOKIE, $_SESSION - Request-scoped proxies (fiber-safe for future async)
  • header(), http_response_code(), echo - Direct output control in SAPI environments
  • \Locale::setDefault(), date_default_timezone_set() - Engine-level configuration

Helpers when they genuinely simplify:

$users = db()->query("SELECT * FROM users WHERE active = ?", [1])->fetchAll();
echo render('user/profile', ['user' => $user]);
echo t("Hello, {name}!", ['name' => 'World']);
session();  // Starts session if needed

Lazy-Loading Architecture

All features exist, but nothing loads until touched:

mailer();      // Mail transport for sending emails
table(User::class);  // Loads ORM only when used
auth()->check();     // Loads authentication system on demand

This "soft dependency" pattern means:

  • A "Hello World" app uses ~300KB of memory
  • Full-stack enterprise app uses what it needs
  • No bootstrap penalty for unused features

Configuration over code. Override framework services via config files or environment variables:

  • Set DATABASE_URL=mysql://user:pass@host/db for database (works out of the box)
  • Create _config/Psr/Log/LoggerInterface.php to return your logger
  • Framework loads these automatically - no service registration needed

Two Paradigms: Choose What Fits

Mini supports both PSR-7 standard patterns and native PHP patterns. You can mix them in the same application.

PSR-7 Pattern (Standards-Based)

Use PSR-7 ServerRequestInterface and ResponseInterface for framework-agnostic code:

// _routes/api/users.php
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;

return function(ServerRequestInterface $request): ResponseInterface {
    $id = $request->getQueryParams()['id'] ?? null;

    $response = response();
    $response->getBody()->write(json_encode(['user' => $id]));
    return $response->withHeader('Content-Type', 'application/json');
};

When to use: Libraries, packages, sub-applications (Slim, Symfony), testability, framework portability.

Native PHP Pattern (Direct)

Use PHP's native request/response mechanisms directly:

// _routes/api/users.php
$id = $_GET['id'] ?? null;

header('Content-Type: application/json');
echo json_encode(['user' => $id]);

When to use: Simple applications, SAPI environments (FPM, mod_php, RoadRunner), rapid prototyping.

How They Coexist

Mini provides request-scoped proxies for $_GET, $_POST, $_COOKIE, $_SESSION that interact with the PSR-7 ServerRequest:

  • In SAPI environments (FPM, CGI, mod_php): Proxies read from PHP's native superglobals
  • In non-SAPI environments (Swoole, ReactPHP, phasync with Fibers): Proxies read from the PSR-7 request object
  • Controllers can return PSR-7 responses OR echo output - Mini handles both
  • Use header() in SAPI or mini\header() in non-SAPI environments

This design enables:

  • Sub-application mounting: Mount PSR-15 compliant frameworks (Slim, Mezzio, etc.) without dependency conflicts (see "Mounting Sub-Applications")
  • Gradual complexity: Start with echo and $_GET, grow into PSR-7 and controllers as needs evolve
  • Future async support: Native PHP patterns will work in Fiber-based async environments (Swoole, ReactPHP)

Installation

composer require fubber/mini

Quick Start

Create the entry point:

// html/index.php
<?php
require '../vendor/autoload.php';
mini\router();

Create your first route:

// _routes/index.php
<?php
echo "<h1>Hello, World!</h1>";

Start the development server:

vendor/bin/mini serve

Visit http://localhost - you're running!

Building CLI Tools

Mini also provides argument parsing and logging for command-line tools:

composer require fubber/mini
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use function mini\args;

args(args()
    ->withFlag('v', 'verbose')
    ->withRequiredValue('o', 'output')
);

if (args()->getUnparsedArgs()) {
    fwrite(STDERR, "Unknown: " . implode(', ', args()->getUnparsedArgs()) . "\n");
    exit(1);
}

$verbosity = args()->getFlag('verbose');  // 0, 1, 2, 3 for -v, -vv, -vvv
$output = args()->getOption('output');

See docs/cli-tools.md for subcommand patterns, verbosity-controlled logging, and complete examples.

Routing: File System as Routing Table

Mini uses the file system as its routing table. No regex parsing, no route compilation, no routing cache - just OS-level file lookups (microseconds, cached by the kernel).

File-Based Routing

Routes map directly to PHP files in _routes/:

_routes/index.php        → /
_routes/users.php        → /users
_routes/api/posts.php    → /api/posts

Wildcard Routing with _

Use _ as a filename or directory name to match any single path segment:

// _routes/users/_.php - Matches /users/123, /users/john, /users/anything
$userId = $_GET[0];  // Captured value: "123", "john", "anything"
$user = db()->queryOne("SELECT * FROM users WHERE id = ?", [$userId]);
echo json_encode($user);
// _routes/users/_/posts/_.php - Matches /users/{userId}/posts/{postId}
$postId = $_GET[0];   // Rightmost wildcard (nearest to file)
$userId = $_GET[1];   // Next wildcard to the left
$post = db()->queryOne("SELECT * FROM posts WHERE id = ? AND user_id = ?", [$postId, $userId]);
echo json_encode($post);

Wildcard behavior:

  • _.php matches any single segment (e.g., /users/123)
  • _/index.php matches any single segment with trailing slash (e.g., /users/123/)
  • Exact matches take precedence over wildcards
  • Captured values stored in $_GET[0], $_GET[1], etc. (right to left - nearest wildcard is [0])
  • Wildcards match single segments only (won't match across /)

Examples:

URL: /users/123           → _routes/users/_.php          ($_GET[0] = "123")
URL: /users/123/          → _routes/users/_/index.php    ($_GET[0] = "123")
URL: /users/john/posts/5  → _routes/users/_/posts/_.php  ($_GET[0] = "5", $_GET[1] = "john")

Why right-to-left? If you move _routes/users/_/posts/_.php to _routes/_/posts/_.php, the code using $_GET[0] for post ID still works - only $_GET[1] changes.

Trailing Slash Redirects

The router automatically redirects to ensure consistency:

  • If only _.php exists: /users/123/ → 301 redirect to /users/123
  • If only _/index.php exists: /users/123 → 301 redirect to /users/123/
  • If both exist: Each URL serves its respective file (no redirect)

What route files can return:

  • Nothing (echo output directly)
  • PSR-7 ResponseInterface
  • Callable that returns PSR-7 response
  • Controller instance with attributes
  • PSR-15 RequestHandlerInterface
// _routes/users.php - Direct output (native PHP)
header('Content-Type: application/json');
echo json_encode(['users' => db()->query("SELECT * FROM users")->fetchAll()]);
// _routes/users.php - PSR-7 response
return response()->json(['users' => db()->query("SELECT * FROM users")->fetchAll()]);

Controller-Based Routing

File-based routing doesn't mean "no OOP." Use __DEFAULT__.php to mount controllers with attribute-based routing:

// _routes/users/__DEFAULT__.php - Handles /users/*
use mini\Controller\AbstractController;
use mini\Controller\Attributes\{GET, POST, PUT, DELETE};

return new class extends AbstractController {
    #[GET('/')]
    public function index(): array
    {
        return db()->query("SELECT * FROM users")->fetchAll();
    }

    #[GET('/{id}/')]
    public function show(int $id): array
    {
        $user = db()->query("SELECT * FROM users WHERE id = ?", [$id])->fetch();
        if (!$user) throw new \mini\Exceptions\NotFoundException();
        return $user;
    }

    #[POST('/')]
    public function create(): array
    {
        db()->exec(
            "INSERT INTO users (name, email) VALUES (?, ?)",
            [$_POST['name'], $_POST['email']]
        );
        return ['id' => db()->lastInsertId(), 'message' => 'Created'];
    }

    #[PUT('/{id}/')]
    public function update(int $id): array
    {
        db()->exec(
            "UPDATE users SET name = ?, email = ? WHERE id = ?",
            [$_POST['name'], $_POST['email'], $id]
        );
        return ['message' => 'Updated'];
    }

    #[DELETE('/{id}/')]
    public function delete(int $id): ResponseInterface
    {
        db()->exec("DELETE FROM users WHERE id = ?", [$id]);
        return $this->empty(204);
    }
};

Key benefits:

  • Scoped routing: /users/123/ becomes /{id}/ inside the controller
  • Type-aware parameters: int $id automatically extracts and casts URL parameter
  • Converter integration: Return arrays, strings, or domain objects - auto-converted to JSON/text
  • Attribute-based: Routes declared with method attributes (no manual registration)

URL mapping:

  • GET /users/index() → returns array → JSON response
  • GET /users/123/show(int $id)$id = 123 (typed!)
  • POST /users/create() → uses $_POST directly
  • DELETE /users/123/delete(int $id) → returns 204 No Content

When to use controllers:

  • Multiple related endpoints (CRUD operations)
  • Type-safe URL parameters
  • Return value conversion (arrays → JSON)
  • Clean, declarative routing

Exception Handling

Mini uses transport-agnostic exceptions that are mapped to appropriate responses by the dispatcher:

// Throw domain exceptions - dispatcher handles HTTP mapping
throw new \mini\Exceptions\NotFoundException('User not found');        // → 404
throw new \mini\Exceptions\AccessDeniedException('Login required');           // → 401/403
throw new \mini\Exceptions\BadRequestException('Invalid email format');       // → 400

Debug mode shows detailed error pages with stack traces. In production, clean error pages are shown.

Custom error pages: Create _errors/404.php, _errors/500.php, etc. to override default error pages. The exception is available as $exception.

For complete coverage of routing, error handling, converters, and web app patterns, see docs/web-apps.md.

Dynamic Routes with __DEFAULT__.php

Handle dynamic segments with pattern matching:

// _routes/blog/__DEFAULT__.php
return [
    '/' => 'index.php',                              // /blog/
    '/{slug}' => fn($slug) => "post.php?slug=$slug", // /blog/my-post
    '/{year}/{month}' => 'archive.php',              // /blog/2025/11
];

Mounting Sub-Applications

Mini's zero-dependency design enables mounting entire frameworks as sub-applications without dependency conflicts. Each sub-app can have its own vendor/ directory with different dependency versions.

Example: Mount a Slim 4 Application

// _routes/api/__DEFAULT__.php
require_once __DIR__ . '/api-app/vendor/autoload.php';  // Slim's autoloader

use Slim\Factory\AppFactory;

$app = AppFactory::create();

// Define Slim routes
$app->get('/users', function ($request, $response) {
    $response->getBody()->write(json_encode(['users' => []]));
    return $response->withHeader('Content-Type', 'application/json');
});

$app->post('/users', function ($request, $response) {
    $data = $request->getParsedBody();
    // ... handle user creation
    return $response->withStatus(201);
});

// Return the Slim app (implements RequestHandlerInterface)
return $app;

Project structure with mounted apps:

project/
├── _routes/
│   ├── index.php              # Mini native route
│   ├── api/
│   │   ├── __DEFAULT__.php    # Mounts Slim app
│   │   └── api-app/           # Complete Slim application
│   │       ├── composer.json  # Slim's dependencies (guzzle 7.x)
│   │       └── vendor/        # Slim's vendor directory
│   └── admin/
│       ├── __DEFAULT__.php    # Mounts Symfony app
│       └── admin-app/         # Complete Symfony application
│           ├── composer.json  # Symfony's dependencies (guzzle 6.x)
│           └── vendor/        # Symfony's vendor directory
├── composer.json              # Mini (no dependencies!)
└── vendor/                    # Mini's vendor directory

How It Works

  1. Mini has zero required dependencies - only PSR interfaces (dev/suggest)
  2. Sub-apps are isolated - each has its own vendor/autoload.php
  3. PSR-7 bridges everything - Mini provides ServerRequestInterface, sub-apps return ResponseInterface
  4. No conflicts - Slim can use guzzlehttp/psr7:7.x, Symfony can use 6.x, no collision

Supported Sub-Applications

Any framework/application that:

  • Implements Psr\Http\Server\RequestHandlerInterface (PSR-15), OR
  • Is a callable accepting ServerRequestInterface and returning ResponseInterface (PSR-7)

Examples:

  • Slim 4 - Native PSR-15 support
  • Mezzio (formerly Zend Expressive) - Native PSR-15 support
  • Symfony - Via PSR-15 adapters (e.g., symfony/psr-http-message-bridge)
  • Custom PSR-15 middleware stacks
  • Any PSR-7/PSR-15 compliant application

Why This Matters

Traditional monorepos fail when dependencies conflict. With Mini:

  • Marketing team uses Slim 4 with latest dependencies
  • Support team maintains legacy Symfony 4 app with old dependencies
  • API team writes new endpoints in Mini native code
  • All three run in one application - no Docker, no microservices, no reverse proxy routing

Database

Mini implements DatabaseInterface with two backends:

PDODatabase - Thin wrapper over PDO:

$users = db()->query("SELECT * FROM users WHERE active = ?", [1]);
$user = db()->queryOne("SELECT * FROM users WHERE id = ?", [123]);

db()->exec("INSERT INTO users (name, email) VALUES (?, ?)", ['John', 'john@example.com']);
db()->transaction(function() {
    db()->exec("INSERT INTO users (name) VALUES (?)", ['John']);
});

VirtualDatabase - SQL interface to non-SQL data (CSV, JSON, APIs):

$vdb = new VirtualDatabase();
$vdb->registerTable('countries', CsvTable::fromFile('data/countries.csv'));

// Query CSV files with SQL
foreach ($vdb->query("SELECT * FROM countries WHERE continent = ?", ['Europe']) as $row) {
    echo $row['name'];
}

Security Pattern: ::mine() as Authorization Boundary

Prevent accidental data leaks by making authorization the default:

class User {
    public static function mine(): PartialQuery {
        $userId = auth()->getUserId();
        // Only return users accessible to current user
        return self::query()->where('id = ? OR EXISTS (...)', [$userId]);
    }
}

// Secure by default - always use ::mine()
$user = User::mine()->eq('id', 123)->one();  // Returns null if not authorized
$friends = User::mine()->limit(50);          // Only authorized users
db()->update(User::mine()->eq('id', 123), ['bio' => 'New']);  // Authorization enforced

// Key insight: ::mine() is shorter than ::query(), so developers naturally use the secure method!

See src/Database/README.md for complete documentation.

Internationalization

Best Practice: Use t() and fmt() everywhere to make your app translatable from day one.

// Always use t() for user-facing text (even in English)
echo t("Hello, {name}!", ['name' => $user->name]);
echo t("You have {count, plural, =0{no messages} one{# message} other{# messages}}",
    ['count' => $messageCount]);

// Always use fmt() for numbers, dates, and currency
echo fmt()->currency($price, 'USD');     // Locale-aware: "$1,234.56" or "1 234,56 $"
echo fmt()->dateShort($order->date);     // "11/15/2025" or "15.11.2025"
echo fmt()->number($revenue);            // "1,234,567.89" or "1.234.567,89"

Per-Request Locale/Timezone

Set locale and timezone per request based on user preferences:

// bootstrap.php (autoloaded via composer.json)
use mini\Mini;
use mini\Phase;

Mini::$mini->phase->onEnteringState(Phase::Ready, function() {
    // Get user's preferred locale from session, cookie, or Accept-Language header
    $locale = $_SESSION['locale'] ?? $_COOKIE['locale'] ?? 'en_US';
    $timezone = $_SESSION['timezone'] ?? 'UTC';

    // Set for this request
    \Locale::setDefault($locale);
    date_default_timezone_set($timezone);
});

Translation files mirror your source code structure in _translations/. For example, strings in _routes/index.php go to _translations/de/_routes/index.php.json:

{
    "Hello, {name}!": "Hallo, {name}!",
    "You have {count, plural, =0{no messages} one{# message} other{# messages}}":
        "Sie haben {count, plural, =0{keine Nachrichten} one{# Nachricht} other{# Nachrichten}}"
}

See src/I18n/README.md for complete documentation, including the vendor/bin/mini translations tool for managing translation files.

Authentication

Simple authentication with pluggable user providers:

// Check authentication
if (!auth()->check()) {
    redirect('/login');
}

// Require login (throws exception if not authenticated)
mini\require_login();

// Role-based access
mini\require_role('admin');

// Login
if (auth()->login($username, $password)) {
    redirect('/dashboard');
}

// Logout
auth()->logout();

Templates

Pure PHP templates with inheritance support:

// Render a template
echo render('user/profile', ['user' => $user]);

Templates support multi-level inheritance:

// _views/user/profile.php
<?php $this->extend('layouts/main.php'); ?>
<?php $this->block('title', 'User Profile'); ?>
<?php $this->block('content'); ?>
    <h1><?= htmlspecialchars($user->name) ?></h1>
    <p><?= t("Member since {date}", ['date' => fmt()->dateShort($user->created)]) ?></p>
<?php $this->end(); ?>

// _views/layouts/main.php
<!DOCTYPE html>
<html>
<head><title><?php $this->show('title', 'Untitled'); ?></title></head>
<body><?php $this->show('content'); ?></body>
</html>

See src/Template/README.md for complete documentation.

Lifecycle Hooks

Hook into application lifecycle via phase transitions:

use mini\Mini;
use mini\Phase;

// Before Ready phase (authentication, CORS, rate limiting)
Mini::$mini->phase->onEnteringState(Phase::Ready, function() {
    // Check authentication
    if (!isset($_SESSION['user_id']) && str_starts_with($_SERVER['REQUEST_URI'], '/admin')) {
        http_response_code(401);
        exit;
    }
});

// After Ready phase (output buffering, response processing)
Mini::$mini->phase->onEnteredState(Phase::Ready, function() {
    ob_start(function($buffer) {
        // Minify HTML
        return preg_replace('/\s+/', ' ', $buffer);
    });
});

Configuration

Environment Variables (.env)

Create a .env file in your project root for environment-specific configuration:

# .env - Not committed to version control

# Database (MySQL/PostgreSQL)
DATABASE_DSN="mysql:host=localhost;dbname=myapp;charset=utf8mb4"
DATABASE_USER="myapp_user"
DATABASE_PASS="secret_password"

# Or use SQLite (default if no config)
# DATABASE_DSN="sqlite:/path/to/database.sqlite3"

# Mini framework settings
MINI_LOCALE="en_US"
MINI_TIMEZONE="America/New_York"
DEBUG=true

# Application salt for security (generate with: openssl rand -hex 32)
MINI_SALT="your-64-character-random-hex-string-here"

# Optional: Custom paths
MINI_ROOT="/path/to/project"
MINI_DOC_ROOT="/path/to/project/html"

Load environment variables with vlucas/phpdotenv or similar:

composer require vlucas/phpdotenv
// bootstrap.php
require __DIR__ . '/vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

Bootstrap File (bootstrap.php)

Create a bootstrap file for application initialization, autoloaded via composer.json:

{
    "autoload": {
        "files": ["bootstrap.php"]
    }
}
// bootstrap.php - Runs before every request
require __DIR__ . '/vendor/autoload.php';

// Load environment variables
if (file_exists(__DIR__ . '/.env')) {
    $dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
    $dotenv->load();
}

// Register lifecycle hooks
use mini\Mini;
use mini\Phase;

// Set locale/timezone per request from user session
Mini::$mini->phase->onEnteringState(Phase::Ready, function() {
    session();  // Start session

    // Get user's preferred locale/timezone
    $locale = $_SESSION['locale'] ?? $_ENV['MINI_LOCALE'] ?? 'en_US';
    $timezone = $_SESSION['timezone'] ?? $_ENV['MINI_TIMEZONE'] ?? 'UTC';

    \Locale::setDefault($locale);
    date_default_timezone_set($timezone);
});

// Global error handler (optional)
set_error_handler(function($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});

Database Configuration

Mini works out of the box with SQLite (_database.sqlite3 in project root). Configure via environment variables:

# MySQL
DATABASE_URL=mysql://user:password@localhost:3306/myapp

# PostgreSQL
DATABASE_URL=postgresql://user:password@localhost/myapp

# SQLite (explicit path)
DATABASE_URL=sqlite:///var/data/myapp.db

Use MINI_DATABASE_URL to override DATABASE_URL (useful when coexisting with other frameworks).

Don't forget to run composer dump-autoload after modifying composer.json!

APCu Polyfill

Mini provides zero-configuration APCu polyfills enabling you to use apcu_* functions even when the APCu extension isn't installed. This is particularly useful for:

  • L1 caching - Sub-millisecond cache operations faster than filesystem or network I/O
  • Shared memory - Data shared across requests/workers (where supported)
  • Framework internals - Mini uses APCu for hot-path optimizations (e.g., PathsRegistry file resolution)

How It Works

Mini automatically provides APCu functionality through the best available driver:

  1. Native APCu (when apcu extension is installed) - Uses real shared memory
  2. Swoole\Table (when Swoole extension is installed) - Coroutine-safe shared memory
  3. PDO SQLite (when pdo_sqlite extension available) - Persistent storage in /dev/shm (tmpfs)
  4. Array fallback - Process-scoped only (no cross-request persistence)

No configuration required - the polyfill loads automatically and selects the best driver.

Usage

Use APCu functions as if the extension were installed:

// Store value with 60-second TTL
apcu_store('user:123', $userData, 60);

// Fetch value
$user = apcu_fetch('user:123', $success);
if ($success) {
    echo "Cache hit!";
}

// Atomic entry (fetch-or-compute pattern)
$config = apcu_entry('app:config', function() {
    return loadHeavyConfiguration();
}, ttl: 300);

// Check existence
if (apcu_exists('session:abc123')) {
    echo "Session exists";
}

// Delete
apcu_delete('user:123');

// Clear all
apcu_clear_cache();

Driver Configuration

Swoole Table Driver:

# .env
MINI_APCU_SWOOLE_SIZE=4096          # Number of rows (default: 4096)
MINI_APCU_SWOOLE_VALUE_SIZE=4096    # Max value size in bytes (default: 4096)

SQLite Driver:

# .env
MINI_APCU_SQLITE_PATH=/dev/shm/my_custom_cache.sqlite  # Custom path (optional)

By default, SQLite uses /dev/shm/apcu_mini_{hash}.sqlite on Linux (tmpfs-backed, RAM speed with persistence) or sys_get_temp_dir() otherwise.

Performance Characteristics

Driver Speed Persistence Cross-Request Cross-Process
Native APCu Fastest RAM only
Swoole\Table Very Fast RAM only ✓ (workers)
SQLite (/dev/shm) Fast
Array Instant None

When Mini Uses APCu

Mini uses APCu internally for L1 caching in performance-critical paths:

  • PathsRegistry (src/Util/PathsRegistry.php) - Caches file resolution results (views, routes, translations, config) with 1-second TTL
  • Future: Translation file loading, metadata caching (opt-in)

Garbage Collection

APCu polyfill drivers implement probabilistic garbage collection (similar to PHP sessions):

  • 1% chance of GC on each apcu_store() or apcu_entry() call
  • Automatically removes expired entries
  • No manual cleanup required

Complete API

All standard APCu functions are polyfilled:

  • apcu_add() - Store if key doesn't exist
  • apcu_cache_info() - Get cache statistics
  • apcu_cas() - Compare-and-swap (atomic update)
  • apcu_clear_cache() - Clear all entries
  • apcu_dec() - Decrement numeric value
  • apcu_delete() - Delete one or more keys
  • apcu_enabled() - Check if APCu is available
  • apcu_entry() - Atomic fetch-or-compute
  • apcu_exists() - Check if key(s) exist
  • apcu_fetch() - Fetch value(s)
  • apcu_inc() - Increment numeric value
  • apcu_key_info() - Get key metadata
  • apcu_sma_info() - Get shared memory info
  • apcu_store() - Store value(s)

Installation for Production

For best performance in production, install the native APCu extension:

# Debian/Ubuntu
sudo apt-get install php-apcu

# Alpine Linux (Docker)
apk add php83-apcu

# PECL
pecl install apcu

The polyfill automatically detects and uses native APCu when available.

Directory Structure

Directories starting with _ are not web-accessible:

project/
├── .env               # Environment variables (not committed)
├── bootstrap.php      # Application initialization (autoloaded)
├── composer.json      # Dependencies and autoload configuration
├── _routes/           # Route handlers
├── _views/            # Templates
├── _config/           # Service configuration
├── _translations/     # Translation files
├── html/              # Document root (web-accessible)
│   ├── index.php      # Entry point
│   └── assets/        # CSS, JS, images
└── vendor/            # Composer dependencies

Development Server

vendor/bin/mini serve                    # http://localhost
vendor/bin/mini serve --port 3000        # Custom port
vendor/bin/mini serve --host 0.0.0.0     # Bind to all interfaces

Documentation

Essential Guides

  • docs/WHY-MINI.md - Why choose Mini? Honest discussion of trade-offs vs. Laravel/Symfony
  • PATTERNS.md - Service overrides, middleware patterns, output buffering
  • REFERENCE.md - Complete API reference
  • CHANGE-LOG.md - Breaking changes (Mini is in active development)

Feature Documentation

Detailed documentation for each framework feature:

CLI Documentation Browser

vendor/bin/mini docs --help              # See available commands
vendor/bin/mini docs mini                # Browse mini namespace
vendor/bin/mini docs "mini\Mini"         # Class documentation

License

MIT License - see LICENSE file.

API Reference: Functions (32)

  1. args() — Get or set the current ArgManager instance for CLI argument parsing
  2. async() — Get the configured async runtime
  3. auth() — Get the Auth facade instance
  4. bootstrap() — Bootstrap the mini framework for controller files
  5. cache() — Get cache instance
  6. can() — Check authorization
  7. collator() — Get the application's Collator instance for locale-aware string comparison
  8. convert() — Convert a value to a target type
  9. csrf() — Create a CSRF token for a specific action
  10. current_url() — Get current URL
  11. db() — Get the database service instance
  12. dispatch() — Dispatch the current HTTP request
  13. flash_get() — Retrieve and clear all flash messages from the session
  14. flash_set() — Flash message functions
  15. fmt() — Get a formatter instance for convenience
  16. h() — Escape HTML output
  17. inference() — Get the inference service instance
  18. log() — Get the application logger instance
  19. mailer() — Get the mailer instance for sending emails
  20. metadata() — Get or create a Metadata instance
  21. redirect() — Redirect to URL and exit
  22. render() — Render a template with provided variables
  23. request() — Get the current ServerRequest
  24. router() — Main entry point for file-based routing
  25. sqlval() — Convert a value to SQL-bindable scalar
  26. t() — Translation function - creates a Translatable instance
  27. url() — Generate URL with proper relative path resolution and optional CDN support
  28. uuid() — Generate a new UUID/GUID.
  29. uuid4() — Generate a UUID v4 (cryptographically random).
  30. uuid7() — Generate a UUID v7 (time-ordered + cryptographically random).
  31. validator() — Get or create a Validator instance
  32. vdb() — Get a VirtualDatabase session for the current request scope

API Reference: Classes (258)

  • Auth\Authentication System
  • Auth final — Authentication facade providing convenience methods
  • Authorizer\Authorization System
  • Ability final — Standard authorization abilities for entity operations
  • Authorization — Authorization service
  • AuthorizationQuery — Query object passed to authorization handlers
  • CLI\Command Line Interface
  • ArgManager — Command-line argument parser with subcommand support
  • ReadlineManager — Wrapper around PHP's readline callback interface with proper signal handling
  • TTY — Terminal output helper
  • Cache\PSR-16 SimpleCache
  • ApcuCache — APCu-backed PSR-16 SimpleCache implementation
  • DatabaseCache — Database-backed PSR-16 SimpleCache implementation
  • FilesystemCache — Filesystem-backed PSR-16 SimpleCache implementation
  • NamespacedCache — Namespaced cache proxy
  • TmpSqliteCache — SQLite-backed PSR-16 SimpleCache implementation for /tmp
  • Controller\Attribute-Based Routing for Controllers
  • Attributes\
  • DELETE — DELETE route attribute
  • GET — GET route attribute
  • PATCH — PATCH route attribute
  • POST — POST route attribute
  • PUT — PUT route attribute
  • Route — Route attribute for controller methods
  • AbstractController abstract — Base controller class with routing and response helpers
  • ConverterHandler — Request handler that converts controller method return values to PSR-7 responses
  • Router — Controller-level router with type-aware route registration
  • Converter\Type Conversion System
  • ClosureConverter — Converter that wraps a typed closure
  • ConverterRegistry — Registry for type converters
  • Database\Database
  • Attributes\Database Attributes
  • Column — Maps property to database column
  • ForeignKey — Specifies foreign key relationship
  • Index — Creates database index
  • NotMapped — Excludes property from database mapping
  • PrimaryKey — Marks property as primary key
  • Table — Maps entity class to database table
  • Virtual\Virtual Database System
  • Collation — Helper functions for creating common Collator configurations
  • AstOptimizer — Optimizes SQL AST for correct evaluation and performance
  • BindableTable final — Internal table wrapper with parameter binding support
  • Dehydrator final — Converts between entity objects and SQL-compatible arrays
  • ExpressionEvaluator — Evaluates SQL AST expressions against a row context
  • PDODatabase — PDO-based database implementation
  • PDOService — PDO Service Factory
  • PartialQuery final — Immutable query builder for composable SQL queries
  • Query final — User-facing query class for reading data
  • QueryTimeoutException — Thrown when a query exceeds the configured timeout
  • ResultSet — Simple result set wrapper for raw SQL queries
  • Session — Database session with isolated temporary tables
  • SqlDialect final — SQL dialect enumeration for database-specific SQL generation
  • VirtualDatabase — Virtual database that executes SQL against registered TableInterface instances
  • WriteValidator final — Validates data before database writes
  • Dispatcher\Request Lifecycle Manager
  • Dispatcher — Request dispatcher
  • HttpDispatcher — HTTP request dispatcher
  • Exceptions\Framework Exception Classes
  • AccessDeniedException — Exception thrown when access to a resource is denied
  • BadRequestException — Exception thrown when a request is malformed or invalid
  • ConfigurationRequiredException — Exception thrown when a required configuration file is missing
  • ContainerException — Exception thrown for service container errors
  • DependencyInjectionException — Thrown when dependency injection fails
  • MissingDependencyException — Thrown when an optional dependency is required but not installed
  • NotFoundException — Exception thrown when a requested service is not found in the container
  • Hooks\Event Dispatcher System
  • Dispatcher abstract — Abstract event dispatcher - root class for Mini's hooks system
  • Event — Event dispatcher for events that can trigger multiple times
  • Filter — Chain of listeners that transform a value
  • Handler — Event where first non-null response wins
  • PerItemTriggers — Event dispatcher that triggers once per source (string or object)
  • StateMachine — A state machine which validates that states only transition to legal target states.
  • Trigger — Event that can only trigger ONCE
  • Http\PSR-7 HTTP Messages & Error Handling
  • Client\PSR-18 HTTP Client
  • ClientException — Base exception for HTTP client errors
  • HttpClient — PSR-18 compliant HTTP client built on curl
  • NetworkException — Exception thrown for network errors (DNS, connection, timeout)
  • RequestException — Exception thrown for malformed requests
  • Message\
  • FileResponse — Response for serving files with automatic MIME type detection
  • HtmlResponse — HTML response with Content-Type: text/html; charset=utf-8
  • JsonResponse — JSON response with Content-Type: application/json
  • Request — Representation of an outgoing, client-side request.
  • Response — Representation of a response from the application to the client
  • ServerRequest — Representation of an incoming, server-side HTTP request.
  • Stream — Describes a data stream.
  • UploadedFile — Value object representing a file uploaded through an HTTP request.
  • Uri — Class simplifies working with uris
  • ErrorHandler — HTTP Error Handler
  • RequestGlobalProxy — ArrayAccess proxy for request globals ($_GET, $_POST, $_COOKIE)
  • ResponseAlreadySentException — Exception thrown when a response has already been sent
  • I18n\Internationalization
  • Fmt — Stateless formatting utility that queries the current request locale
  • Translatable — Translatable string class that implements Stringable
  • Translator — Translator class responsible for loading and managing translations
  • Inference\
  • InferenceException — Exception thrown when inference fails
  • Logger\Mini Logger
  • Logger — Built-in logger implementation that logs to PHP's error_log
  • ScopedLogger final — Logger decorator that prefixes messages with a scope identifier
  • Mail\Mini Mail
  • Base64Stream — Base64 Encoding Stream
  • Email — Email - High-level email composition with lazy MIME compilation
  • MailTransportException — Exception thrown when mail transport fails
  • Mailbox — Mailbox - RFC 5322 email address with optional display name
  • Mailer final — Mail sending with envelope handling and Bcc stripping
  • Message — MIME Message - Single-part message (text, HTML, attachment, etc.)
  • MultipartMessage — Multipart Message
  • MultipartMessageStream — Streaming reader for MultipartMessage body
  • MultipartType final — Multipart MIME types
  • NativeMailTransport — Mail transport using PHP's native mail() function
  • QuotedPrintableStream — Quoted-Printable Encoding Stream
  • SendmailTransport — Mail transport using the sendmail binary
  • Metadata\Metadata System
  • Attributes\
  • DefaultValue — Set metadata default value annotation
  • Description — Set metadata description annotation
  • Examples — Set metadata examples annotation
  • IsDeprecated — Mark field as deprecated in metadata
  • IsReadOnly — Mark field as read-only in metadata
  • IsWriteOnly — Mark field as write-only in metadata
  • MetaFormat — Set format hint in metadata
  • Property — Define metadata for a property on a class/interface without an actual property
  • Ref — Reference another class's metadata for this property
  • Title — Set metadata title annotation
  • AttributeMetadataFactory — Builds metadata from PHP class attributes
  • Metadata — JSON Schema annotation builder
  • MetadataStore — Registry for metadata instances with auto-building from attributes
  • Mini\Core Framework Components
  • ApcuDrivers\APCu Polyfill Drivers
  • ApcuDriverFactory — Documentation missing
  • ArrayApcuDriver — ArrayApcuDriver - Simple in-memory APCu polyfill using static array
  • PDOSqlite3ApcuDriver — Documentation missing
  • SwooleTableApcuDriver — Documentation missing
  • PathRegistries — Container for path registries used by the framework
  • Parsing\
  • SQL\
  • AST\
  • ASTNode abstract — Abstract base class for all AST nodes
  • BetweenOperation — BETWEEN operation node
  • BinaryOperation — Binary operation node (e.g., a = b, x > 5, col AND col2)
  • CaseWhenNode — CASE expression node
  • ColumnDefinition — Column definition in CREATE TABLE
  • ColumnNode — Column reference in SELECT clause
  • CreateIndexStatement — CREATE INDEX statement node
  • CreateTableStatement — CREATE TABLE statement node
  • DeleteStatement — DELETE statement node
  • DropIndexStatement — DROP INDEX statement node
  • DropTableStatement — DROP TABLE statement node
  • ExistsOperation — EXISTS operation AST node
  • FunctionCallNode — Function call node (e.g., COUNT(*), MAX(col), COUNT(DISTINCT col))
  • IdentifierNode — Identifier node (table names, column names)
  • InOperation — IN / NOT IN operation node
  • IndexColumn — Index column specification
  • InsertStatement — INSERT statement node
  • IsNullOperation — IS NULL / IS NOT NULL operation node
  • JoinNode — JOIN clause node
  • LikeOperation — LIKE / NOT LIKE operation node
  • LiteralNode — Literal value node (strings, numbers, NULL)
  • NiladicFunctionNode — Niladic function node (SQL standard functions without parentheses)
  • PlaceholderNode — Placeholder node (? or :name)
  • QuantifiedComparisonNode — Quantified comparison node - col op ALL/ANY (SELECT ...)
  • SelectStatement — SELECT statement node
  • SubqueryNode — Subquery node - a SELECT statement used as a value expression
  • TableConstraint — Table-level constraint in CREATE TABLE
  • UnaryOperation — Unary operation node (e.g., -5, NOT expr)
  • UnionNode — Set operation node (UNION, INTERSECT, EXCEPT)
  • UpdateStatement — UPDATE statement node
  • WindowFunctionNode — Window function node - func() OVER (...)
  • WithStatement — WITH clause wrapper (Common Table Expressions)
  • AstParameterBinder — Binds parameters to AST by replacing placeholders with literal values
  • SqlLexer — SQL Lexer - Tokenizes SQL strings
  • SqlParser — SQL Parser - Recursive Descent Implementation
  • SqlRenderer — Renders AST nodes back to SQL strings
  • SqlSyntaxException — SQL Syntax Exception with rich error reporting
  • DelimitedNode final — DelimitedNode
  • GenericParser final — GenericParser
  • NodeList final — NodeList
  • TextNode final — TextNode
  • Router\File-Based Routing
  • Redirect — Exception to redirect routing to a different target
  • Reroute — Exception for pattern-based routing in __DEFAULT__.php files
  • Router — Simple file-based router for Mini framework
  • Session\Fiber-Safe Session Management
  • Session — Cache-backed session implementation
  • SessionMiddleware — PSR-15 middleware that adds session cookies to responses
  • SessionProxy — Global proxy for $_SESSION that auto-starts sessions on access
  • Static\Static File Serving
  • StaticFiles — Static File Serving Middleware
  • Table\
  • Index\
  • BTreeIndex final — Append-only B-tree index with on-disk persistence.
  • BTreeInternalPage final — Parsed internal page - children are page numbers, keys are separators.
  • BTreeLeafPage final — Parsed leaf page - stores raw page data and parses lazily.
  • LsmIndex final — LSM (Log-Structured Merge) index for dynamic insert-heavy workloads.
  • SortedArrayIndex final — Simple hash + lazy sorted array for range queries.
  • TreapIndex final — Hybrid hash/sorted-array/treap index optimized for real-world access patterns.
  • TreapNode final — Documentation missing
  • Types\
  • ColumnType final — Column data type for comparison semantics
  • IndexType final — Type of index on a column
  • Operator final — Documentation missing
  • Utility\
  • ColumnMappedSet — Wraps a SetInterface to remap column names
  • EmptyTable final — Empty table with schema
  • PredicateFilter final — Applies a bound Predicate to a TableInterface using filter methods
  • Set — Simple in-memory set implementation
  • SingleRowTable final — A table with exactly one row and dynamic columns
  • Wrappers\
  • AbstractTableWrapper abstract — Base class for table wrappers that delegate to a source table
  • AliasTable — Wrapper that applies table/column aliasing to a source table
  • BarrierTable final — Barrier that prevents filter/order pushdown to preserve result set membership
  • ConcatTable — Concatenation of two tables (UNION ALL semantics)
  • CrossJoinTable — Cross join (Cartesian product) of two tables
  • DebugTable — Debug wrapper that logs operations reaching the implementation
  • DistinctTable — Table wrapper that removes duplicate rows
  • ExceptTable — Set difference table (rows in source but NOT in excluded set)
  • ExistsTable — Filters outer table rows based on existence in inner table
  • FilteredTable — Filters rows from source table using a column/operator/value condition
  • FullJoinTable — Full outer join of two tables with ON condition
  • InnerJoinTable — Inner join of two tables with equi-join condition
  • LeftJoinTable — Left join of two tables with ON condition
  • OptimizingTable — Adaptive optimization wrapper that measures and improves table access patterns
  • OrTable — Applies OR predicates to source table in-memory
  • RightJoinTable — Right join of two tables with ON condition
  • SortedTable — Sorted table wrapper
  • SqlExceptTable — SQL EXCEPT - rows from left that don't exist in right
  • SqlIntersectTable — SQL INTERSECT - rows from left that also exist in right
  • UnionTable — Union of two tables (set union / OR operation)
  • AbstractTable abstract — Base class for all table implementations
  • ArrayTable — Pure PHP array-backed in-memory table implementation
  • CSVTable — Table backed by CSV data
  • ColumnDef — Column definition with type and optional index metadata
  • GeneratorTable — Simple table backed by a generator/closure
  • InMemoryTable — SQLite-backed in-memory table implementation
  • Index final — Index factory and key encoding utilities.
  • JSONTable — Table backed by JSON data
  • OrderDef — Order specification for a single column
  • Predicate final — Immutable predicate for filtering conditions
  • Template\PHP Template Rendering
  • Renderer — Default template renderer with inheritance support
  • TemplateContext final — Template context - the $this object available in templates
  • Test\
  • SqlLogicTest — SQLLogicTest parser and runner
  • SqlLogicTestRecord — A single test record (statement or query)
  • SqlLogicTestResult — Test run results
  • UUID\Universally Unique Identifiers
  • UUID4Factory — Generates UUID v4 identifiers using cryptographically secure randomness.
  • UUID7Factory — Generates UUID v7 identifiers using Unix timestamp (milliseconds) + cryptographically secure randomness.
  • Util\Utility Classes
  • Math\
  • Int\
  • BcMathInt final — bcmath-based implementation of IntValue
  • GmpInt final — GMP-based implementation of IntValue
  • NativeInt final — Pure PHP arbitrary precision integer using decimal limbs (base 10^9)
  • PyInt final — Reference implementation using Python interpreter
  • BigInt final — Immutable arbitrary precision integer
  • Decimal final — Immutable fixed-point decimal with BigInt backing
  • DecimalMath final — Arbitrary precision decimal math using integer math with scaling
  • Expr final — Expression tree with lazy evaluation
  • ExprParser final — Infix to expression tree parser using shunting-yard algorithm
  • CacheControlHeader — Immutable Cache-Control header manipulation
  • IdentityMap final — Identity map pattern implementation with weak references
  • InstanceStore — Generic instance store that mirrors WeakMap API but with type validation
  • MachineSalt — Generate a stable, machine-specific salt for cryptographic operations
  • Path final — Cross-platform path manipulation utility
  • PathsRegistry — Registry for managing multiple paths with priority-based file resolution
  • QueryParser — QueryParser - Parse and match query string criteria
  • Validator\JSON Schema Validation
  • Attributes\
  • Enum — Validate via enum()
  • ExclusiveMaximum — Validate via exclusiveMaximum()
  • ExclusiveMinimum — Validate via exclusiveMinimum()
  • Field — Define a field validator on a class/interface without a property
  • Format — Validate via format()
  • MaxItems — Validate via maxItems()
  • MaxLength — Validate via maxLength()
  • MaxProperties — Validate via maxProperties()
  • Maximum — Validate via maximum()
  • MinItems — Validate via minItems()
  • MinLength — Validate via minLength()
  • MinProperties — Validate via minProperties()
  • Minimum — Validate via minimum()
  • MultipleOf — Validate via multipleOf()
  • Pattern — Validate via pattern()
  • Required — Validate via required()
  • Type — Validate via type()
  • UniqueItems — Validate via uniqueItems()
  • AttributeValidatorFactory — Builds validators from PHP class attributes
  • Purpose final — Standard validation purposes for entity lifecycle operations
  • ValidationError — Represents validation errors for both scalar values and complex objects
  • Validator — Composable validation builder
  • ValidatorStore — Registry for validator instances with auto-building from attributes
  • CSRF — WordPress-inspired nonce (CSRF) token system
  • Collection final — Immutable collection with functional transformation methods
  • Lifetime final — Service lifetime for dependency injection container
  • Mini final — Core framework singleton that manages application configuration and service container.
  • Phase final — Application lifecycle phases
  • Test abstract — Base class for structured tests
  • ValidationException — Exception thrown when validation fails