Building modern web apps shouldn't require learning 50 new concepts. Sometimes you just want to write PHP.
The Problem with Modern PHP Frameworks
Don't get me wrong—Laravel, Symfony, and other frameworks are incredible. But sometimes you're building a simple web app and you find yourself:
- 📚 Reading documentation for hours just to create a basic form
- 🔧 Configuring dozens of services you don't need
- 🐘 Fighting with complex abstractions for simple tasks
- ⚡ Waiting for slow development servers to restart
What if there was a better way?
Meet Lighthouse 🚨
Lighthouse is a minimal, predictable PHP micro-framework that embraces the simplicity PHP was meant for. It's designed around one core principle: get productive immediately.
<?php
// That's it. Your first route.
route('/', function() {
return view('home.php', ['message' => 'Hello World!']);
});
Why Lighthouse is Different
1. Logic Where It Makes Sense
Instead of forcing everything through controllers, Lighthouse lets you handle form logic directly in views—the way PHP was designed:
<?php
// views/contact.php
$errors = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = sanitize_email($_POST['email']);
$message = sanitize_string($_POST['message']);
if (!validate_email($email)) {
$errors[] = 'Invalid email';
}
if (empty($errors)) {
db_insert('contacts', ['email' => $email, 'message' => $message]);
$success = 'Message sent!';
}
}
?>
<form method="POST">
<?php if ($success ?? false): ?>
<div class="success"><?= $success ?></div>
<?php endif; ?>
<input type="email" name="email" required>
<textarea name="message" required></textarea>
<button type="submit">Send</button>
</form>
Self-contained. Predictable. No magic.
2. Modern Stack, Zero Configuration
- PHP 8+ with type hints and modern features
- SQLite for zero-config databases
- HTMX for dynamic interactions
- Pico.css for beautiful, minimal styling
# Get started in 30 seconds
lighthouse new my-app
cd my-app
php -S localhost:8000 -t public/
3. Security by Default
// CSRF protection built-in
<?= csrf_field() ?>
// Input sanitization included
$clean_input = sanitize_string($_POST['data']);
// Rate limiting ready
if (!check_rate_limit($_SERVER['REMOTE_ADDR'])) {
// Handle rate limit
}
4. Database Operations That Make Sense
// Simple, predictable database operations
$users = db_select('users', ['active' => 1]);
$user_id = db_insert('users', ['name' => $name, 'email' => $email]);
db_update('users', ['last_login' => date('Y-m-d H:i:s')], ['id' => $user_id]);
Real-World Example: Authentication in 5 Minutes
Here's how you build a complete login system:
<?php
// routes.php
route('/login', function() {
return view('login.php');
});
route('/dashboard', function() {
if (!auth_user()) {
header('Location: /login');
exit;
}
return view('dashboard.php');
});
<?php
// views/login.php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = sanitize_email($_POST['email']);
$password = $_POST['password'];
$user = db_select_one('users', ['email' => $email]);
if ($user && auth_verify_password($password, $user['password'])) {
auth_login($user['id']);
header('Location: /dashboard');
exit;
}
$error = 'Invalid credentials';
}
?>
<form method="POST">
<?php if ($error ?? false): ?>
<div class="error"><?= $error ?></div>
<?php endif; ?>
<input type="email" name="email" required>
<input type="password" name="password" required>
<?= csrf_field() ?>
<button type="submit">Login</button>
</form>
That's it. No controllers, no middleware configuration, no service providers. Just PHP doing what PHP does best.
When to Use Lighthouse
Lighthouse shines when you're building:
- 🚀 MVPs and prototypes - Get to market fast
- 📊 Internal tools and dashboards - No need for complexity
- 🏢 Small business websites - Contact forms, simple e-commerce
- 🎓 Learning projects - Focus on concepts, not framework magic
- 🔧 API backends - Lightweight and fast
The Philosophy
Lighthouse embraces pragmatic PHP development:
- Start simple - Use logic in views for rapid development
- Refactor when needed - Move to more complex patterns as you grow
- Choose what fits - Multiple approaches supported
- Stay productive - Don't over-engineer simple problems
Getting Started
# Install the CLI
bash -c "$(curl -fsSL https://raw.githubusercontent.com/max-yterb/Lighthouse/main/scripts/install.sh)"
# Create your first app
lighthouse new my-awesome-app
cd my-awesome-app
# Start building
php -S localhost:8000 -t public/
What's Next?
Lighthouse is actively developed with a focus on:
- 🔐 Enhanced authentication providers (OAuth, SAML)
- 🗄️ Multiple database support (MySQL, PostgreSQL)
- ⚡ Performance monitoring tools
- 📱 Advanced HTMX integration patterns
Try It Today
If you're tired of complex frameworks for simple projects, give Lighthouse a try. It might just remind you why you fell in love with PHP in the first place.
- 📖 Documentation: max-yterb.github.io/Lighthouse
- 💻 GitHub: github.com/max-yterb/Lighthouse
- 💬 Discussions: GitHub Discussions
What do you think? Are you ready to try a framework that gets out of your way? Drop a comment below with your thoughts on modern PHP development!
Tags: #php #webdev #framework #opensource #microframework
Top comments (6)
The first thing when I looked at the code is that the framework isn't using Composer. Any reason why?
Yes. Composer and Object Orientation are overhead. Add complexity to something simple like Web Programming. Ideally Function programming is better then OO.
A web endpoint is essentially a function that takes a Request as its input and produces a Response as its output.
You can think of it like this in conceptual, language-agnostic terms:
A Request is a structured bundle of intentions. It carries things like the HTTP method (GET, POST, etc.), the path the client wants, headers describing capabilities or identity, and sometimes a body full of data. It’s the caller knocking on your door with a package and a wishlist.
A Response is your side of the handshake. It contains a status code that expresses how things went, headers that communicate metadata, and optionally a body that holds document data, JSON, HTML, or whatever artifact your server produces. It’s your packaged reply to the visitor.
That is a bold take. And I can understand the perspective.
Composer is more than an object autoloader. It provides a base file structure. You can use functions without needing to explicitly include the files.
Check this repository. Its main functionality is in the src/functions.php file. The objects are there mainly to provide a stricter type hinting than you can get from primitives.
PHP is a multi paradigm language, and to get the cleanest code you use the strengths of the paradigms that are available.
You still need to add which function you want to use in the PHP files. So it goes from
include '../includes/db.php';touse function Lighthouse\Framework\db_insert;. Using Composer makes it more specific.You are loading all your functions in the index.php file by including the files that include functions, so instead of doing that let Composer take care of that for you.
People that are going to use your framework, are going to want to add Composer packages because writing everything from scratch is too much work. Even for small websites. So they are going to add
include vendor/autoload.phpto the index.php file. And then the problems can start to happen because you didn't namespace the functions.Even if there is a reason why not to use Composer, there are multiple reasons why your framework should use it. The benefits outweigh the negatives.
The only PHP solution that doesn't uses Composer is Wordpress. And that is a mess of a framework.
The full docs are now online: max-yterb.github.io/Lighthouse/