andrevanzuydam / tina4php
Tina4 PHP — This is not a 4ramework
Requires
- php: >=8.2
- ext-json: *
- ext-openssl: *
Requires (Dev)
- phpunit/phpunit: ^10 || ^11
- v3.x-dev
- v3.9.4
- v3.9.3
- v3.9.2
- v3.9.1
- v3.9.0
- v3.8.7
- v3.8.3
- v3.8.2
- v3.8.1
- v3.8.0
- v3.7.2
- v3.7.1
- v3.7.0
- v3.6.0
- v3.5.0
- v3.4.0
- v3.3.0
- v3.2.2
- v3.2.1
- v3.2.0
- v3.1.2
- 3.1.0
- 3.0.0-rc.1
- v2.x-dev
- v2.1.2
- v2.1.1
- v2.1.0
- v2.0.99
- v2.0.98
- v2.0.97
- v2.0.96
- v2.0.95
- v2.0.94
- v2.0.93
- v2.0.92
- v2.0.91
- v2.0.90
- v2.0.89
- v2.0.88
- v2.0.87
- v2.0.86
- v2.0.85
- v2.0.84
- v2.0.83
- v2.0.82
- v2.0.81
- v2.0.80
- v2.0.79
- v2.0.78
- v2.0.77
- v2.0.76
- v2.0.75
- v2.0.74
- v2.0.73
- v2.0.72
- v2.0.71
- v2.0.70
- v2.0.69
- v2.0.68
- v2.0.67
- v2.0.64
- v2.0.63
- v2.0.62
- v2.0.61
- v2.0.60
- v2.0.59
- v2.0.58
- v2.0.57
- v2.0.56
- v2.0.55
- v2.0.54
- v2.0.53
- v2.0.52
- v2.0.51
- v2.0.50
- v2.0.49
- v2.0.48
- v2.0.47
- v2.0.46
- v2.0.45
- v2.0.44
- v2.0.43
- v2.0.42
- v2.0.41
- v2.0.40
- v2.0.39
- v2.0.38
- v2.0.37
- v2.0.36
- v2.0.35
- v2.0.34
- v2.0.33
- v2.0.32
- v2.0.31
- v2.0.30
- v2.0.29
- v2.0.28
- v2.0.27
- v2.0.26
- v2.0.25
- v2.0.24
- v2.0.23
- v2.0.22
- v2.0.21
- v2.0.20
- v2.0.19
- v2.0.18
- v2.0.17
- v2.0.16
- v2.0.15
- v2.0.14
- v2.0.13
- v2.0.12
- v2.0.11
- v2.0.10
- v2.0.9
- v2.0.8
- v2.0.7
- v2.0.6
- v2.0.5
- v2.0.4
- v2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
- v0.1.123
- v0.1.122
- v0.1.121
- v0.1.120
- v0.1.119
- v0.1.118
- v0.1.117
- v0.1.116
- v0.1.115
- v0.1.114
- v0.1.113
- v0.1.112
- v0.1.111
- v0.1.110
- v0.1.109
- v0.1.108
- v0.1.107
- v0.1.106
- v0.1.105
- v0.1.104
- v0.1.103
- v0.1.102
- v0.1.101
- v0.1.100
- v0.1.99
- v0.1.98
- v0.1.97
- v0.1.96
- v0.1.95
- v0.1.94
- v0.1.93
- v0.1.92
- v0.1.91
- v0.1.90
- v0.1.89
- v0.1.88
- v0.1.87
- v0.1.86
- v0.1.85
- v0.1.84
- v0.1.83
- v0.1.82
- v0.1.81
- v0.1.80
- v0.1.79
- v0.1.78
- v0.1.77
- v0.1.76
- v0.1.75
- v0.1.74
- v0.1.73
- v0.1.72
- v0.1.71
- v0.1.70
- v0.1.69
- v0.1.68
- v0.1.67
- v0.1.66
- v0.1.64
- v0.1.63
- v0.1.62
- v0.1.61
- v0.1.60
- v0.1.59
- v0.1.58
- v0.1.57
- v0.1.56
- v0.1.55
- v0.1.54
- v0.1.53
- v0.1.52
- v0.1.51
- v0.1.50
- v0.1.49
- v0.1.48
- v0.1.47
- v0.1.46
- v0.1.45
- v0.1.44
- v0.1.43
- v0.1.42
- v0.1.41
- v0.1.40
- v0.1.39
- v0.1.38
- v0.1.37
- v0.1.36
- v0.1.35
- v0.1.34
- v0.1.33
- v0.1.32
- v0.1.31
- v0.1.30
- v0.1.29
- v0.1.28
- v0.1.27
- v0.1.26
- v0.1.25
- v0.1.24
- v0.1.23
- v0.1.22
- v0.1.21
- v0.1.20
- v0.1.19
- v0.1.18
- v0.1.17
- v0.1.16
- v0.1.15
- v0.1.14
- v0.1.13
- v0.1.12
- v0.1.11
- v0.1.10
- v0.1.9
- v0.1.8
- v0.1.7
- v0.1.6
- v0.1.5
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.0.100
- v0.0.99
- v0.0.98
- v0.0.97
- v0.0.96
- v0.0.95
- v0.0.94
- v0.0.93
- v0.0.92
- v0.0.91
- v0.0.90
- v0.0.89
- v0.0.88
- v0.0.87
- v0.0.86
- v0.0.85
- v0.0.84
- v0.0.83
- v0.0.82
- v0.0.81
- v0.0.80
- v0.0.79
- v0.0.78
- v0.0.77
- v0.0.76
- v0.0.75
- v0.0.74
- v0.0.73
- v0.0.72
- v0.0.71
- v0.0.70
- v0.0.69
- v0.0.68
- v0.0.67
- v0.0.66
- v0.0.65
- v0.0.64
- v0.0.63
- v0.0.62
- v0.0.61
- v0.0.60
- v0.0.59
- v0.0.58
- v0.0.57
- v0.0.56
- v0.0.55
- v0.0.54
- v0.0.53
- v0.0.52
- v0.0.51
- v0.0.50
- v0.0.49
- v0.0.48
- v0.0.47
- v0.0.46
- v0.0.45
- v0.0.44
- v0.0.43
- v0.0.42
- v0.0.41
- v0.0.40
- v0.0.39
- v0.0.38
- v0.0.37
- v0.0.36
- v0.0.35
- v0.0.34
- v0.0.33
- v0.0.32
- v0.0.31
- v0.0.30
- v0.0.29
- v0.0.28
- v0.0.27
- v0.0.26
- v0.0.25
- v0.0.24
- v0.0.23
- v0.0.22
- v0.0.21
- v0.0.20
- v0.0.19
- v0.0.18
- v0.0.17
- v0.0.16
- v0.0.15
- v0.0.14
- v0.0.13
- v0.0.12
- v0.0.11
- v0.0.10
- v0.0.9
- v0.0.8
- v0.0.7
- v0.0.6
- v0.0.5
- v0.0.4
- v0.0.2
- dev-main
This package is auto-updated.
Last update: 2026-03-27 11:07:25 UTC
README
Tina4 PHP
This is not a framework
Laravel joy. PHP speed. 10x less code. Zero third-party dependencies.
Documentation • Getting Started • Features • CLI Reference • tina4.com
Quick Start
# Install the Tina4 CLI cargo install tina4 # or download 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:7146 — your app is running.
Without the Tina4 CLI
# 1. Create project mkdir my-app && cd my-app composer require tina4stack/tina4php # 2. Create entry point cat > index.php << 'EOF' <?php require_once 'vendor/autoload.php'; $app = new \Tina4\App(basePath: __DIR__); $server = new \Tina4\Server('0.0.0.0', 7146); $server->start(); EOF # 3. Create .env echo 'TINA4_DEBUG=true' > .env echo 'TINA4_LOG_LEVEL=ALL' >> .env # 4. Create route directory mkdir -p src/routes # 5. Run php index.php
What's Included
Every feature is built from scratch -- no bloated vendor trees, no third-party runtime dependencies in core.
| Category | Features |
|---|---|
| HTTP | Built-in PHP server, static route registration, path params ({id}, {name}), middleware pipeline, CORS, rate limiting |
| Templates | Frond engine (Twig-compatible), inheritance, partials, filters, macros, fragment caching, sandboxing |
| ORM | Active Record, typed properties, soft delete, relationships (hasOne/hasMany/belongsTo with eager loading), field mapping, table filters, multi-database |
| Database | SQLite3, PostgreSQL, MySQL, MSSQL, Firebird -- unified adapter interface, query caching (TINA4_DB_CACHE=true for 4x speedup) |
| Auth | Zero-dep JWT (HS256/RS256), sessions (file/Redis/Valkey/MongoDB/database), password hashing, form tokens |
| API | Swagger/OpenAPI auto-generation, GraphQL with ORM auto-schema and GraphiQL IDE, WSDL/SOAP with auto WSDL |
| Background | Queue (SQLite/RabbitMQ/Kafka/MongoDB) with priority, delayed jobs, retry, batch processing |
| Real-time | Native WebSocket (RFC 6455), stream_select server, per-path routing, connection manager, broadcast |
| Frontend | tina4-css (~24 KB), frond.js helper, SCSS compiler, live reload, CSS hot-reload |
| DX | Dev admin dashboard, error overlay, request inspector, hot-reload (stream_select file watcher), AI tool integration, Carbonah green benchmarks |
| Data | Migrations with rollback and status, 26+ fake data generators, ORM and table seeders |
| Other | REST client, localization (i18n), cache (memory/Redis/file), event system, messenger (.env driven), configurable error pages, HTML element builder, health check |
1,421 tests across 38 built-in features. Zero dependencies. All Carbonah benchmarks rated A+.
For full documentation visit tina4.com.
Install
composer require tina4stack/tina4php
Built-in database adapters
v3 ships with adapters for SQLite3, MySQL, PostgreSQL, MSSQL (sqlserver), and Firebird -- no extra packages needed. Just ensure the required PHP extension is installed (e.g. ext-sqlite3, ext-pdo_mysql).
Getting Started
1. Create a project
composer require tina4stack/tina4php
composer exec tina4 initialize:run
This creates:
my-app/
├── index.php # Entry point
├── .env # Configuration
├── src/
│ ├── routes/ # API + page routes (auto-discovered)
│ ├── orm/ # Database models
│ ├── app/ # Service classes and shared helpers
│ ├── templates/ # Frond/Twig templates
│ ├── services/ # Background service processes
│ ├── scss/ # SCSS (auto-compiled to public/css/)
│ └── public/ # Static assets served at /
├── migrations/ # SQL migration files
└── tests/ # PHPUnit tests
2. Create a route
Create src/routes/hello.php:
use Tina4\Router; use Tina4\Request; use Tina4\Response; Router::get("/api/hello", function (Request $request, Response $response) { return $response(["message" => "Hello from Tina4!"], HTTP_OK); }); Router::get("/api/hello/{name}", function (Request $request, Response $response) { $name = $request->params["name"]; return $response(["message" => "Hello, {$name}!"], HTTP_OK); });
Visit http://localhost:7146/api/hello -- routes are auto-discovered, no imports needed.
3. Add a database
Edit .env:
[DATABASE] DATABASE_PATH=test.db
Create and run a migration:
composer tina4 migrate:create "create users table"
Edit the generated SQL:
CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL, created_at TEXT DEFAULT CURRENT_TIMESTAMP );
composer tina4 migrate
4. Create an ORM model
Create src/orm/User.php:
class User extends \Tina4\ORM { public $tableName = "users"; public $primaryKey = "id"; public $id; public $name; public $email; public $createdAt; }
5. Build a REST API
Create src/routes/users.php:
use Tina4\Router; use Tina4\Request; use Tina4\Response; Router::get("/api/users", function (Request $request, Response $response) { $users = (new User())->select("*", 100)->asArray(); return $response($users, HTTP_OK); }); Router::get("/api/users/{id}", function (Request $request, Response $response) { $user = new User(); $user->load($request->params["id"]); return $response($user->asArray(), HTTP_OK); }); Router::post("/api/users", function (Request $request, Response $response) { $user = new User($request->body); $user->save(); return $response($user->asArray(), HTTP_CREATED); });
6. Add a template
Create src/templates/base.twig:
<!DOCTYPE html> <html> <head> <title>{% block title %}My App{% endblock %}</title> <link rel="stylesheet" href="/css/tina4.min.css"> {% block stylesheets %}{% endblock %} </head> <body> {% block content %}{% endblock %} <script src="/js/frond.js"></script> {% block javascripts %}{% endblock %} </body> </html>
Create src/templates/pages/home.twig:
{% extends "base.twig" %}
{% block content %}
<div class="container mt-4">
<h1>{{ title }}</h1>
<ul>
{% for user in users %}
<li>{{ user.name }} -- {{ user.email }}</li>
{% endfor %}
</ul>
</div>
{% endblock %}
Render it from a route:
Router::get("/", function (Request $request, Response $response) { $users = (new User())->select("*", 20)->asArray(); return $response->template("pages/home.twig", ["title" => "Users", "users" => $users]); });
7. Seed, test, deploy
composer test # Run test suite composer start # Start dev server
For the complete step-by-step guide, visit tina4.com.
Features
Routing
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(); Router::get("/api/admin/stats", function (Request $request, Response $response) { return $response(["secret" => true], HTTP_OK); })->secure();
Path parameters: {id}, {name}, {slug}. Middleware chaining with ->middleware([...]).
ORM
Active Record with typed properties, validation, soft delete, relationships, and multi-database support.
class User extends \Tina4\ORM { public $tableName = "users"; public $primaryKey = "id"; public $softDelete = true; public $id; public $name; public $email; public $role; // Relationships public $hasMany = [["Address" => "customerId"]]; public $hasOne = [["Profile" => "userId"]]; } // CRUD $user = new User(["name" => "Alice", "email" => "alice@example.com"]); $user->save(); $user->load("email = 'alice@example.com'"); $user->delete(); // Queries $users = (new User())->select("*", 100)->asArray();
Database
Unified interface via DatabaseFactory::create():
use Tina4\Database\DatabaseFactory; $db = DatabaseFactory::create("app.db"); $db = DatabaseFactory::create("sqlite::memory:"); $db = DatabaseFactory::create("mysql://localhost:3306/mydb", username: "user", password: "pass"); $db = DatabaseFactory::create("postgres://localhost:5432/mydb", username: "user", password: "pass"); $db = DatabaseFactory::create("mssql://localhost:1433/mydb", username: "sa", password: "pass"); $db = DatabaseFactory::create("firebird://localhost:3050/path/to/db", username: "SYSDBA", password: "masterkey"); $result = $db->fetch("SELECT * FROM users WHERE age > ?", 20, 0);
Middleware
Router::get("/protected", function (Request $request, Response $response) { return $response(["secret" => true], HTTP_OK); })->middleware(["AuthCheck"]);
JWT Authentication
$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. Chain ->noAuth() to make public, ->secure() to protect GET routes.
Sessions
$_SESSION["user_id"] = 42; $userId = $_SESSION["user_id"];
GraphQL
// Auto-schema from ORM models // GET /graphql -> GraphiQL IDE // POST /graphql -> Execute queries // Query example: // { users { id, name, email } }
Swagger / OpenAPI
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); });
Service Runner
class EmailService extends \Tina4\Process { public function run(): void { // Long-running background process while ($this->isRunning()) { $this->processQueue(); sleep(5); } } }
Start with: composer start-service
Template Engine (Frond)
Twig-compatible, filters, macros, inheritance, fragment caching:
{% 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 %}
CRUD Scaffolding
Auto-generate admin interfaces from ORM models with built-in CRUD operations.
Event System
\Tina4\Events::on("user.created", function ($name) { file_put_contents("./log/event.log", "New user: {$name}\n", FILE_APPEND); }); \Tina4\Events::emit("user.created", "Alice");
REST Client
$api = new \Tina4\Api("https://api.example.com", "Bearer xyz"); $result = $api->sendRequest("/users/42");
SCSS Compiler
Drop .scss files in src/scss/ -- auto-compiled to CSS. Variables, nesting, mixins, @import, @extend.
Localization (i18n)
JSON translation files with placeholder interpolation.
Annotation-Driven Testing
/** * @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; }
Dev Mode
Set TINA4_DEBUG=true in .env to enable:
- Twig debug extension --
{{ dump(variable) }}available in templates - Verbose logging -- full debug output via
Debug::message() - No template caching -- templates recompile on every request
- Error detail -- full stack traces shown in the browser
CLI Reference
composer tina4 # Tina4 menu composer exec tina4 initialize:run # Scaffold a new project composer start # Start dev server (default: 7146) composer start 8080 # Start on specific port composer start --production # Auto-use OPcache + best production config composer tina4 migrate # Run pending migrations composer tina4 migrate:create <desc> # Create a migration file composer tina4 generate model <name> # Generate ORM model scaffold composer tina4 generate route <name> # Generate route scaffold composer tina4 generate migration <desc> # Generate migration file composer tina4 generate middleware <name># Generate middleware scaffold composer test # Run test suite composer start-service # Start background service runner
Production Server Auto-Detection
tina4 serve auto-detects the best production configuration:
- PHP: OPcache enabled, optimized settings
- Use
composer start --productionto auto-apply production configuration
Scaffolding with tina4 generate
Quickly scaffold new components:
composer tina4 generate model User # Creates src/orm/User.php composer tina4 generate route users # Creates src/routes/users.php composer tina4 generate migration "add age" # Creates migration SQL file composer tina4 generate middleware AuthLog # Creates middleware class
ORM Relationships & Eager Loading
// Relationships defined on the model public $hasMany = [["Order" => "userId"]]; public $hasOne = [["Profile" => "userId"]]; public $belongsTo = [["Customer" => "customerId"]]; // Eager loading with include $users = (new User())->select("*", 100, include: ["orders", "profile"])->asArray();
DB Query Caching
Enable query caching for up to 4x speedup on read-heavy workloads:
# .env
TINA4_DB_CACHE=true
Frond Pre-Compilation
Templates are pre-compiled for 2.8x faster rendering.
Gallery
7 interactive examples with Try It deploy.
Environment
[Section] TINA4_DEBUG=true # Enable debug mode DATABASE_PATH=app.db # SQLite database path SECRET=your-jwt-secret # JWT signing secret TINA4_LOCALE=en # Localization language [SWAGGER] SWAGGER_TITLE=My API # Swagger page title SWAGGER_DESCRIPTION=API docs # Swagger description [DEPLOYMENT] GIT_BRANCH=master # Git branch for deployments GIT_SECRET=0123456789 # Webhook secret
Zero-Dependency Philosophy
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. The pcntl extension is optional (used for graceful signal handling on Linux/macOS). Database drivers are optional and installed separately. This keeps the full deployment under 8MB and minimizes your project's carbon footprint.
Docker Support
docker run -v $(pwd):/app tina4stack/php:latest composer require tina4stack/tina4php docker run -v $(pwd):/app tina4stack/php:latest composer exec tina4 initialize:run docker run -v $(pwd):/app -p7146:7146 tina4stack/php:latest composer start
Documentation
Full guides, API reference, and examples at tina4.com.
License
MIT (c) 2007-2026 Tina4 Stack https://opensource.org/licenses/MIT
Tina4 -- The framework that keeps out of the way of your coding.
Our Sponsors
Sponsored with 🩵 by Code Infinity
Supporting open source communities • Innovate • Code • Empower