Starter project for ZenPHP — a modern, zero-dependency PHP 8.4 micro-framework.
- PHP 8.4+
- Composer
- PDO extension (SQLite or MySQL)
- OpenSSL extension
composer create-project studiokaizen/skeleton my-app
cd my-app1. Copy the config file and fill in your values:
cp config.example.php config.phpOpen config.php and set your app name, database connection, and any other settings.
2. Generate an encryption key:
php zen key:generateThis writes a secure 32-byte key into config.php automatically.
3. Run migrations:
php zen migrate4. Point your web server's document root to the public/ directory.
For local development with PHP's built-in server:
php -S localhost:8000 -t publicbootstrap/ Application bootstrap (providers, middleware, error handlers)
config.php Your local configuration (gitignored)
config.example.php Configuration template to commit
database/
migrations/ SQL migration files
seeders/ SQL seeder files
public/
index.php Web entry point — define your routes here
.htaccess Apache rewrite rules
resources/
views/ PHP view templates
src/
Events/ Application events
Jobs/ Queued jobs
Providers/ Service providers (AppServiceProvider wired by default)
storage/
app/ Private file storage
cache/ File cache
logs/ Application logs
zen CLI entry point
Open public/index.php — it ships with commented examples covering all common patterns. Uncomment and adapt as needed.
use Zen\Http\Request;
use Zen\Http\Response;
$app->get('/', function (Request $request, Response $response) use ($app): Response {
return $app->view('home');
})->middleware('csrf');
$app->get('/users/:id', function (Request $request, Response $response) use ($app): Response {
$user = $app['db']->table('users')->find((int) $request->getRouteParam('id'));
return $app->view('users/show', compact('user'));
})->middleware('csrf', 'auth');Templates live in resources/views/ and use plain PHP. Extend layout.php using sections:
<?php $this->extend('layout'); ?>
<?php $this->section('title', 'Page Title'); ?>
<?php $this->startSection('content'); ?>
<h1>Hello!</h1>
<?php $this->endSection(); ?>php zen make:migration create_posts_tableEdit the generated file in database/migrations/, then run:
php zen migrateCreate a class in src/Jobs/ extending Zen\Queue\Job:
namespace App\Jobs;
use Zen\Queue\Job;
class SendWelcomeEmail extends Job
{
public function __construct(
public readonly string $email,
) {}
public function handle(): void
{
// send email
}
}Dispatch it from a route handler:
$app['queue']->dispatch(new \App\Jobs\SendWelcomeEmail($email));Process the queue:
php zen queue:workCreate a class in src/Events/ extending Zen\Events\Event:
namespace App\Events;
use Zen\Events\Event;
class UserRegistered extends Event
{
public function __construct(
public readonly int $userId,
public readonly string $email,
) {}
}Register a listener in src/Providers/AppServiceProvider.php:
$app['events']->addListener(\App\Events\UserRegistered::class, function ($event) use ($app): void {
$app['logger']->info("New user #{$event->userId}");
});Dispatch from a route:
$app['events']->dispatch(new \App\Events\UserRegistered($id, $email));php zen list # list all available commands
php zen make:migration <name> # create a migration
php zen make:seeder <name> # create a seeder
php zen migrate # run pending migrations
php zen migrate:rollback # roll back last batch
php zen migrate:fresh --seed # reset + re-migrate + seed
php zen db:seed # run all seeders
php zen queue:work # process queued jobs
php zen schedule:run # run due scheduled tasks
php zen cache:clear # clear file cache
php zen key:generate # generate encryption keyFull API reference at studiokaizen/framework.
MIT