自己搭一个最小 PHP 框架是理解 Laravel 架构的最好方式,比直接读 Laravel 源码有效得多。
项目结构
my-framework/
├── app/
│ └── Controller/
│ └── HomeController.php
├── public/
│ └── index.php
├── src/
│ ├── Router.php
│ ├── Container.php
│ └── Middleware.php
├── vendor/
└── composer.json
第一步:Composer 初始化
mkdir my-framework && cd my-framework
composer init
composer.json:
{
"name": "me/framework",
"autoload": {
"psr-4": {
"App\\": "app/",
"Framework\\": "src/"
}
}
}
生成自动加载文件:
composer dump-autoload
第二步:最小 Router
src/Router.php:
<?php
namespace Framework;
class Router
{
private array $routes = [];
public function get(string $uri, $action): void
{
$this->routes['GET'][$uri] = $action;
}
public function post(string $uri, $action): void
{
$this->routes['POST'][$uri] = $action;
}
public function dispatch(): void
{
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if (isset($this->routes[$method][$uri])) {
call_user_func($this->routes[$method][$uri]);
return;
}
http_response_code(404);
echo "404 Not Found";
}
}
入口文件 public/index.php:
<?php
require '../vendor/autoload.php';
use Framework\Router;
use App\Controller\HomeController;
$router = new Router();
$router->get('/', [HomeController::class, 'index']);
$router->dispatch();
启动:
php -S localhost:8000 -t public
第三步:IoC 容器(依赖注入)
Laravel 的核心是 Container,不是 Router。
src/Container.php:
<?php
namespace Framework;
use ReflectionClass;
class Container
{
private array $bindings = [];
public function bind(string $abstract, callable $factory): void
{
$this->bindings[$abstract] = $factory;
}
public function make(string $class): object
{
if (isset($this->bindings[$class])) {
return ($this->bindings[$class])($this);
}
// 用反射自动解析构造函数依赖
$ref = new ReflectionClass($class);
$constructor = $ref->getConstructor();
if (!$constructor) {
return new $class();
}
$params = array_map(
fn($p) => $this->make($p->getType()->getName()),
$constructor->getParameters()
);
return $ref->newInstanceArgs($params);
}
}
这样 $container->make(HomeController::class) 会自动实例化其所有依赖:
class HomeController
{
public function __construct(
private UserService $userService
) {}
}
第四步:Middleware
请求流程:Request → Middleware → Controller → Response
<?php
namespace Framework;
class Middleware
{
private array $stack = [];
public function add(callable $middleware): void
{
$this->stack[] = $middleware;
}
public function run(callable $handler): void
{
$runner = array_reduce(
array_reverse($this->stack),
fn($next, $mw) => fn() => $mw($next),
$handler
);
$runner();
}
}
示例认证中间件:
$middleware->add(function (callable $next) {
if (!isset($_SESSION['user'])) {
http_response_code(401);
echo '请先登录';
return;
}
$next();
});
第五步:ServiceProvider
<?php
namespace Framework;
abstract class ServiceProvider
{
public function __construct(
protected Container $app
) {}
abstract public function register(): void;
}
示例:
class DatabaseServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->bind('db', fn($app) => new Database(
config('database.host'),
config('database.name')
));
}
}
注册:
(new DatabaseServiceProvider($container))->register();
学习路线
- Router + 自动加载 → 理解 HTTP 分发
- Container + ReflectionClass → 理解依赖注入
- Middleware → 理解 Laravel Pipeline
- ServiceProvider → 理解 Laravel 服务注册
- 自己实现后再看 Laravel 源码,对照理解
完成前 3 步后基本就能看懂 Laravel 入口流程了。
