零依赖不是目的,可控才是。当框架的每一行代码你都能读懂,线上排障就不再是“玄学”。
#为什么选择零依赖
Composer 生态很繁荣,但也带来三个现实问题:
| 问题 | 表现 | 零依赖的收益 |
|---|---|---|
| 依赖膨胀 | 一个博客装进 40+ 个包 | 部署包只有几百 KB |
| 版本地狱 | 升级一个包牵连一片 | 只有自己的代码要维护 |
| 排障困难 | 堆栈 90% 在 vendor | 断点直接落在业务代码 |
依赖越少,不可控的部分就越少。
#路由:从正则到编译缓存
最朴素的路由就是一个 path => handler 映射表,但动态参数必须编译成正则:
public static function get(string $path, mixed $action): RouteItem
{
$pattern = preg_replace('/\{(\w+)\}/', '(?P<$1>[^/]+)', $path);
return self::collection()->add(['GET'], $path, $action, $pattern);
}几个必须处理的细节:
- 参数默认约束为
[^/]+,需要数字时用->where('id', '\d+') - 静态路由优先匹配,避免动态路由“吃掉”
/posts/new - 生产环境把编译结果缓存成 PHP 数组文件
#容器:只做两件事
一个够用的容器只需要支持绑定与自动解析:
public function make(string $class): object
{
if (isset($this->bindings[$class])) {
return $this->bindings[$class]($this);
}
$reflection = new ReflectionClass($class);
$constructor = $reflection->getConstructor();
if ($constructor === null) {
return new $class();
}
$arguments = [];
foreach ($constructor->getParameters() as $parameter) {
$type = $parameter->getType();
$arguments[] = $type instanceof ReflectionNamedType && !$type->isBuiltin()
? $this->make($type->getName())
: null;
}
return $reflection->newInstanceArgs($arguments);
}#中间件洋葱模型
中间件用闭包层层包裹,注意反向遍历:
foreach (array_reverse($middleware) as $entry) {
$handler = fn (Request $request): Response => $instance->handle($request, $handler);
}这样第一个中间件在最外层,既能前置处理,也能后置处理响应。
#小结
- 路由编译结果要可缓存
- 容器保持最小实现,够用就好
- 中间件顺序决定请求生命周期
评论
还没有评论,来说点什么吧。