Copyright (C) 2015-2025 Mark Constable [email protected] (MIT License)
A progressive PHP 8.5 micro-framework tutorial in 10 chapters. Each chapter builds on the previous, demonstrating modern PHP features and design patterns. No Bootstrap - uses custom minimal CSS.
Watch the complete tutorial series on YouTube - 10 chapters with AI narration covering all framework features.
- PHP 8.5+ (for pipe operator
|>) - Composer (for chapters 05-09)
git clone https://github.com/markc/spe
cd spe
composer install
php -S localhost:8000Open http://localhost:8000 to see the chapter index.
For individual chapters with PSR-4 autoloading:
cd 09-Blog/public && php -S localhost:8080| # | Name | Description | Key Feature |
|---|---|---|---|
| 01 | Simple | Single-file anonymous class | Pipe operator basics |
| 02 | Styled | Custom CSS, dark mode | Toast notifications |
| 03 | Plugins | Plugin architecture | CRUDL pattern |
| 04 | Themes | Model/View separation | Multiple layouts |
| 05 | Autoload | PSR-4 autoloading | Composer integration |
| 06 | Session | Session management | State persistence |
| 07 | PDO | Database access | SQLite + QueryType enum |
| 08 | Users | User management | Full CRUDL operations |
| 09 | Blog | Complete CMS | Auth, Blog, Docs, Categories |
| 10 | YouTube | YouTube Manager | OAuth, API, Shared Services |
- First-class callables:
array_keys(...),http_build_query(...) - Enums:
enum QueryType { case All; case One; case Column; } - Readonly properties
- Readonly classes:
readonly class Init true,false,nullas standalone types
- Typed class constants:
private const string DEFAULT = 'home' - Typed array constants:
private const array OPTIONS = [...] #[\Override]attribute
- Asymmetric visibility:
public private(set) string $prop newwithout parentheses
- Pipe operator:
$value |> trim(...) |> strtolower(...) - Chained transformations with first-class callables
URL: ?o=Home&m=list&t=TopNav
o = Object/Plugin name
m = Method/Action (CRUDL: create, read, update, delete, list)
t = Theme (Simple, TopNav, SideBar)
index.phpcreatesInit(new Ctx)Initprocesses URL parameters and checks auth{Plugin}Model->$method()returns data array{Plugin}View->$method()renders HTML (or falls back to Theme)Init->__toString()outputs response
XX-Chapter/
├── public/
│ └── index.php # Entry point
└── src/
├── Core/ # Framework classes
├── Plugins/ # Feature plugins (Model + View)
└── Themes/ # Layout themes
No Bootstrap! Uses custom spe.css (~270 lines):
- CSS variables for light/dark theming
@media (prefers-color-scheme: dark)automatic dark mode- Manual toggle via localStorage
- Responsive layouts (TopNav, SideBar)
- Dropdown menus with fade animation
- Toast notifications
- Blog card grid and prose styling
<?php declare(strict_types=1);
// Copyright (C) 2015-2025 Mark Constable <[email protected]> (MIT License)
// PHP 8.3 Typed constant
private const string DEFAULT = 'home';
// PHP 8.4 Asymmetric visibility
public private(set) string $page;
// PHP 8.5 Pipe operator for transformation chains
$value = $input
|> trim(...)
|> (fn($s) => filter_var($s, FILTER_SANITIZE_URL))
|> (fn($v) => $v ?: self::DEFAULT);
// First-class callable with pipe
$nav = $pages
|> array_keys(...)
|> (fn($k) => array_map(fn($n) => "<a href=\"?m=$n\">$n</a>", $k))
|> (fn($a) => implode(' | ', $a));
// PHP 8.3 Override attribute
#[\Override] public function list(): array {
return ['head' => 'Home', 'main' => 'Welcome'];
}All chapters 02-10 use shared CSS/JS from the project root:
/spe.css- Complete styling with CSS variables/spe.js- Theme toggle, toast notifications, dropdown handling
Chapter 01-Simple has no external dependencies (inline minimal styles only).
Chapter 10-YouTube requires Google API credentials in ~/.config/google/client_secret.json.
MIT License - See individual file headers for copyright notices.