One framework, four languages, 140 features, zero runtime dependencies.
Translation pending
Developer toolsPHP · TwigGitHub @tina4stackOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Tina4 PHP composer repository
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Tina4 PHP
The Intelligent Native Application 4ramework
140 cataloged features. Zero dependencies. One require, everything works.
Open http://localhost:7145 -- your app is running.
Every feature is built from scratch -- no bloated vendor trees, no third-party runtime dependencies in core.Read the full README ↗# Install the Tina4 CLI (one-time, cross-language)
cargo install tina4 # or download a binary from https://github.com/tina4stack/tina4/releases
# Create a project
tina4 init php ./my-app
# Run it
cd my-app && tina4 serve
Open http://localhost:7145 -- your app is running.
# 1. Install
composer require tina4stack/tina4php
# 2. Entry point
echo '<?php require "vendor/autoload.php"; (new Tina4\App())->run();' > index.php
# 3. .env
echo 'TINA4_DEBUG=true' > .env
# 4. Run (no file watching in this mode)
composer start
Every feature is built from scratch -- no bloated vendor trees, no third-party runtime dependencies in core.
| Category | Features |
|---|---|
| Core HTTP (7) | Router with path params ({id:int}, {p:path}), Server, Request/Response, Middleware pipeline, Static file serving, CORS |
| Database (6) | SQLite, PostgreSQL, MySQL, MSSQL, Firebird -- unified adapter, connection pooling, query cache, transactions, race-safe ID generation, SQL dialect translation |
| ORM (7) | Active Record with typed fields, relationships (has_one/has_many/belongs_to), soft delete, QueryBuilder + MongoDB support, Auto-CRUD generator, migrations with rollback |
| Auth & Security (5) | JWT (HS256/HS384/HS512 via core hash_hmac, no extension; RS256 opt-in via suggested ext-openssl), password hashing (PBKDF2-SHA256), API key validation, rate limiting, CSRF form tokens |
| Templating (3) | Frond engine (Twig/Jinja2-compatible, pre-compiled 2.8x faster), SCSS auto-compilation, built-in CSS (~24 KB) |
| API & Integration (5) | HTTP client (zero-dep), GraphQL with ORM auto-schema + GraphiQL IDE, WSDL/SOAP with auto WSDL, WebSocket (RFC 6455) + Redis backplane, MCP server (24 dev tools) |
| Background (3) | Job queue (File/RabbitMQ/Kafka/MongoDB) with priority, delay, retry, dead letters -- service runner -- event system (on/emit/once/off) |
| Data & Storage (4) | Session (File/Redis/Valkey/MongoDB/DB), response cache (LRU, TTL), seeder + 50+ fake data generators, messenger (SMTP/IMAP) |
| Developer Tools (7) | Dev dashboard (11 tabs), dev toolbar, error overlay (Catppuccin Mocha), dev mailbox, hot reload + CSS hot-reload, code metrics (complexity, coupling, maintainability), AI context installer (7 tools) |
| Utilities (7) | DI container (transient + singleton), HtmlElement builder, inline testing (@tests decorator), i18n (6 languages), Swagger/OpenAPI auto-generation, CLI scaffolding (generate model/route/migration/middleware), structured logging |
2,073 tests. Zero dependencies. Full parity across Python, PHP, Ruby, and Node.js.
For full documentation visit tina4.com.
use Tina4\Router;
use Tina4\Request;
use Tina4\Response;
Router::get("/api/items", function (Request $request, Response $response) {
return $response(["items" => []], HTTP_OK);
});
Router::post("/api/webhook", function (Request $request, Response $response) {
return $response(["ok" => true], HTTP_OK);
})->noAuth();
Path parameters: {id}, {name}, {slug}. Middleware chaining with ->middleware([...]). Chain ->secure() to protect GET routes, ->noAuth() to make routes public.
class User extends \Tina4\ORM
{
public $tableName = "users";
public $primaryKey = "id";
public $softDelete = true;
public $id;
public $name;
public $email;
public $hasMany = [["Order" => "userId"]];
public $hasOne = [["Profile" => "userId"]];
public $belongsTo = [["Customer" => "customerId"]];
}
$user = new User($request);
$user->save();
$user->load("email = '[email protected]'");
$user->delete();
$users = (new User())->select("*", 100)->asArray();
Unified interface via Database::create():
use Tina4\Database\Database;
$db = Database::create('sqlite:///app.db');
$db = Database::create('postgres://localhost:5432/mydb', username: 'user', password: 'pass');
$db = Database::create('mysql://localhost:3306/mydb', username: 'root', password: 'secret');
$db = Database::create('mssql://localhost:1433/mydb', username: 'sa', password: 'pass');
$db = Database::create('firebird://localhost:3050/path/to/db.fdb', username: 'SYSDBA', password: 'masterkey');
$result = $db->fetch("SELECT * FROM users WHERE age > ?", [18]);
$token = \Tina4\Auth::getToken(["user_id" => 42], "your-secret");
$payload = \Tina4\Auth::validToken($token, "your-secret");
$claims = \Tina4\Auth::getPayload($token);
POST/PUT/PATCH/DELETE routes require Authorization: Bearer <token> by default.
// File, Redis, Valkey, MongoDB, or database-backed sessions
$_SESSION["user_id"] = 42;
$userId = $_SESSION["user_id"];
Configure via .env:
TINA4_SESSION_HANDLER=redis
TINA4_SESSION_PATH=redis://localhost:6379
use Tina4\Queue;
$queue = new Queue();
$queue->push("email.send", ["to" => "[email protected]", "subject" => "Welcome"]);
$queue->push("report.generate", ["id" => 42], priority: 10, delay: 60);
// Process jobs
$queue->process("email.send", function ($job) {
sendEmail($job["to"], $job["subject"]);
});
Backends: File (default), RabbitMQ, Kafka, MongoDB. Supports priority, delay, retry, and dead letters.
// Auto-schema from ORM models -- no configuration needed
// GET /graphql -> GraphiQL IDE
// POST /graphql -> Execute queries
// Query: { users { id, name, email } }
// Mutation support via ORM save/delete
use Tina4\WebSocket;
$ws = new WebSocket('0.0.0.0', 8080);
$ws->on('message', function ($connection, $message) {
$connection->send("Echo: " . $message);
});
$ws->on('open', function ($connection) {
$connection->send("Welcome!");
});
$ws->start();
Supports RFC 6455, per-path routing, connection manager, broadcast, and Redis backplane for horizontal scaling.
Auto-generated at /swagger:
/**
* @description Get all users
* @tags Users
*/
Router::get("/api/users", function (Request $request, Response $response) {
return $response((new User())->select("*", 100)->asArray(), HTTP_OK);
});
use Tina4\Events;
Events::on("user.created", function ($user) {
sendWelcomeEmail($user);
}, priority: 10);
Events::once("app.boot", function () {
warmCaches();
});
Events::emit("user.created", $userData);
Events::off("user.created");
// Auto WSDL generation from annotated service classes
// Endpoint: /wsdl
$api = new \Tina4\Api("https://api.example.com", "Bearer xyz");
$result = $api->sendRequest("/users/42");
$result = $api->sendRequest("/users", "POST", ["name" => "Alice"]);
use Tina4\AI;
$reply = AI::chat([["role" => "user", "content" => "Summarise this text"]]);
$text = AI::complete("Give me a title");
$vector = AI::embed("semantic search text");
foreach (AI::chat([["role" => "user", "content" => "Stream this"]], stream: true) as $delta) {
echo $delta;
}
Configure TINA4_AI_PROVIDER as local, openai, or anthropic. Hosted providers require TINA4_AI_KEY; local OpenAI-compatible endpoints do not. The AI context/skills installer is Tina4\AITools.
use Tina4\FakeData;
$fake = new FakeData();
$fake->name(); // "Alice Johnson"
$fake->email(); // "[email protected]"
$fake->phone(); // "+1-555-0123"
$fake->address(); // "123 Main St, Springfield"
$fake->paragraph(); // Lorem ipsum...
50+ generators for names, emails, addresses, dates, numbers, text, and more.
use Tina4\Messenger;
$messenger = new Messenger();
$messenger->sendEmail(
"[email protected]",
"Subject Line",
"<h1>Hello</h1><p>Message body</p>"
);
Configure via .env:
SMTP_HOST=smtp.example.com
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=secret
Twig-compatible with pre-compilation for 2.8x faster rendering:
{% extends "base.twig" %}
{% block content %}
<h1>{{ title | upper }}</h1>
{% for item in items %}
<p>{{ item.name }} -- {{ item.price | number_format(2) }}</p>
{% endfor %}
{% include "partials/sidebar.twig" %}
{% endblock %}
$container = new \Tina4\Container();
$container->singleton('db', fn() => Database::create(getenv('DB_URL')));
$container->register('mailer', fn() => new MailService());
$db = $container->get('db'); // same instance every time
$mailer = $container->get('mailer'); // new instance each time
/**
* @tests
* assert (1,1) === 2, "1 + 1 = 2"
* assert is_integer(1,1) === true, "This should be an integer"
*/
function add($a, $b) {
return $a + $b;
}
JSON translation files with placeholder interpolation. Supports 6 languages out of the box.
use Tina4\I18n;
$i18n = new I18n('en');
echo $i18n->translate("welcome.message", ["name" => "Alice"]);
extract(\Tina4\HtmlElement::helpers());
echo $_div(["class" => "card"],
$_h2("Title"),
$_p("Content")
);
Set TINA4_DEBUG=true in .env to enable:
/__dev/) -- admin UI with route inspection, query runner, queue management, WebSocket monitor, dev mailbox, and moretina4 Rust CLI watches src/, migrations/, .env and POSTs /__dev/api/reload; PHP broadcasts to the browser via WebSocket (/__dev_reload) with a polling fallback on GET /__dev/api/mtime. SCSS changes swap the stylesheet without a full reload{{ dump(variable) }} available, no cachingbin/tina4php serve [--port P] [--host H] # Start dev server (default: 0.0.0.0:7145)
bin/tina4php migrate # Run pending migrations
bin/tina4php migrate:create "description" # Create a migration file
bin/tina4php generate model <name> # Generate ORM model scaffold
bin/tina4php generate route <name> # Generate route scaffold
bin/tina4php generate migration <desc> # Generate migration file
bin/tina4php generate middleware <name> # Generate middleware scaffold
bin/tina4php seed # Run database seeders
bin/tina4php ai [--all] # Install AI context files
Or via Composer:
composer start # Start dev server
composer start --production # Start with OPcache + production config
composer test # Run test suite
composer tina4 migrate # Run migrations
composer tina4 generate model User # Scaffold a model
Benchmarked with wrk: 5,000 requests, 50 concurrent, median of 3 runs:
| Framework | JSON req/s | Deps | Features |
|---|---|---|---|
| Tina4 PHP | 29,293 | 0 | 55 |
| Slim | 5,714 | 10+ | ~6 |
| Laravel | 445 | 50+ | ~25 |
Tina4 PHP is 5× faster than Slim and 65× faster than Laravel, with zero dependencies and 140 cataloged features built in.
Across all 4 Tina4 implementations:
| Python | PHP | Ruby | Node.js | |
|---|---|---|---|---|
| JSON req/s | 6,508 | 29,293 | 10,243 | 84,771 |
| Dependencies | 0 | 0 | 0 | 0 |
| Features | 55 | 55 | 55 | 55 |
Tina4 ships the same 140 cataloged features across four languages with full test parity:
| Language | Package | Tests (v3.11.12) |
|---|---|---|
| Python | pip install tina4-python | 2,281 |
| PHP | composer require tina4stack/tina4php | 2,073 |
| Ruby | gem install tina4 | 2,508 |
| Node.js | npm install @tina4/core | 2,897 |
Same routing, same ORM, same templates, same CLI, same dev tools. Learn one, deploy in any.
Key .env variables:
# Core
TINA4_DEBUG=true # Enable debug mode
DATABASE_PATH=app.db # SQLite database path (or use TINA4_DATABASE_URL)
TINA4_DATABASE_URL=postgres://localhost/mydb # Connection URL for any database
SECRET=your-jwt-secret # JWT signing secret
TINA4_LOCALE=en # Localization language
# Database
TINA4_DB_CACHE=true # Enable query caching (4x speedup)
TINA4_AUTOCOMMIT=false # Auto-commit control (default: off)
TINA4_DATABASE_CONNECT_TIMEOUT=10 # Seconds to wait for a connect (0 or less = wait forever)
# Sessions
TINA4_SESSION_HANDLER=file # file, redis, valkey, mongodb, database
TINA4_SESSION_PATH=redis://localhost # Session backend URL
TINA4_SESSION_SAMESITE=Lax # SameSite cookie attribute
# Cache
TINA4_CACHE_TTL=60 # Response cache TTL in seconds
TINA4_CACHE_MAX_ENTRIES=1000 # Max cached responses
# WebSocket
TINA4_WS_BACKPLANE=redis # WebSocket scaling backplane
TINA4_WS_BACKPLANE_URL=redis://localhost # Backplane connection URL
# Swagger
SWAGGER_TITLE=My API # Swagger page title
SWAGGER_DESCRIPTION=API docs # Swagger description
# SMTP
SMTP_HOST=smtp.example.com # Mail server
SMTP_PORT=587 # Mail port
[email protected] # Mail username
SMTP_PASSWORD=secret # Mail password
Tina4 PHP is built from the ground up with no third-party runtime dependencies in core. The framework requires only PHP 8.2+ with openssl and json extensions. Database drivers are optional and installed separately. This keeps the full deployment under 8 MB and minimizes your project's carbon footprint.
A complete e-commerce app lives in example/. It demonstrates every framework feature through a real-world use case.
cd example
bash setup.sh # macOS/Linux
# or: setup.bat # Windows
php index.php
| Role | Password | |
|---|---|---|
| Admin | [email protected] | admin123 |
| Customer | [email protected] | customer123 |
See example/README.md for full details.
Full guides, API reference, and examples at tina4.com.
MPL-2.0. Copyright (c) 2026 Code Infinity. Separate commercial terms are available from Code Infinity. Previously published releases retain their original licences. https://mozilla.org/MPL/2.0/
Sponsored with :blue_heart: by Code Infinity
Supporting open source communities Innovate Code Empower*