Download the PHP package kode/middleware without Composer

On this page you can find all versions of the php package kode/middleware. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package middleware

Kode\Middleware

PHP Version

PSR-15

PSR-7 / PSR-11

License

轻量、可重入、协程安全的 PSR-15 中间件管道,显式串联「路由前 / 路由后 / 调度」三段式生命周期,原生融合 多进程 / 多线程 / Fiber 协程 与 分布式链路透传。

Kode\Middleware 是 kode 生态的「管道底座」:它只负责中间件如何被组织与执行,不实现具体的 CORS / 限流 / 鉴权等业务中间件(这些留给 kode/http 与你的业务层)。它的核心改进点,是针对 kode/http 已有 MiddlewarePipeline 的可变 $index 竞态缺陷,用 不可变管道 + 可重入游标 重构,使管道可以在多进程、多线程、Fiber 协程之间安全共享、可重试、可重入。

核心特性

环境要求

环境 版本要求
PHP >= 8.3
PSR-7 ^1.1 \|\| ^2.0
PSR-15(Server Middleware/Handler) ^1.0
PSR-11(Container) ^1.1 \|\| ^2.0

可选扩展(启用对应能力时)

扩展 / 包 启用能力
kode/context 链路 ID / 请求上下文的协程 / 线程 / 进程隔离
kode/di 用 PSR-11 容器按类名解析并自动装配中间件
kode/fibers Fiber 协程运行器(FiberRunner)
ext-parallel + kode/parallel 多线程运行器(ThreadRunner)
kode/process 多进程运行器(ProcessRunner)
kode/http PSR-7 消息实现与 HTTP 服务端集成

注意:本包不内置 PSR-7 消息实现,运行测试与示例时需引入 nyholm/psr7 或其它实现。

安装

快速开始

三段式管道(推荐用 Pipe 门面)

Pipe 把一次请求的生命周期显式拆成三段,让中间件的位置一目了然:

更底层的 Pipeline

当你不需要「路由前后」分段语义时,直接用 Pipeline:

命名空间快捷函数

composer.json 已通过 files 自动加载 src/functions.php:


API 参考

Pipe(管道构建器 / 门面)

方法 说明
Pipe::create(?ContainerInterface $c, ?Registry $r) 创建构建器
alias(string $name, mixed $mw) 注册中间件别名
group(string $name, array $mw) 注册中间件分组
factory(string $name, \Closure $f) 注册带参工厂(name:arg1,arg2 语法)
beforeRoute(mixed ...$mw) 追加路由前中间件(全局,含 404 请求)
afterRoute(mixed ...$mw) 追加路由后中间件(可读取路由元数据)
router(\Closure\|RouteMiddleware $matcher) 设置路由匹配器
invoker(\Closure $invoker) 自定义路由处理器调用方式
fallback(RequestHandlerInterface\|callable $h) 设置兜底处理器
resolver(ResolverInterface $r) 指定自定义解析器
build(): Pipeline 构建不可变管道(结果缓存)
handle(ServerRequestInterface): ResponseInterface 直接处理一次请求
blueprint(): Blueprint 导出管道蓝图(跨进程 / 跨节点下发)
Pipe::routeOf(ServerRequestInterface): ?RouteResult 读取请求上的路由结果

Pipe 自身可变(链式书写顺手),但 build() 产出的 Pipeline 不可变。

Pipeline(不可变管道内核)

方法 说明
Pipeline::of(array $mw, ?ResolverInterface $r) 静态工厂
add(mixed ...$mw): static 追加中间件,返回新实例
addWithPriority(mixed $mw, int $priority): static 显式优先级追加
prepend(mixed ...$mw): static 插入到最外层,返回新实例
withDestination(RequestHandlerInterface $d): static 设置终点处理器
to(callable $h): static 以可调用对象设终点
withResolver(ResolverInterface $r): static 更换解析器
merge(PipelineInterface $other): static 摊平合并另一条管道
handle(ServerRequestInterface): ResponseInterface 作为处理器执行(可重入)
process(ServerRequestInterface, RequestHandlerInterface): ResponseInterface 作为中间件被调度(嵌套洋葱)
run(ServerRequestInterface, $destination): ResponseInterface 一次性执行
terminate(ServerRequestInterface, ResponseInterface): void 触发 TerminableInterface 收尾回调
stack(): array 已按优先级排序的声明列表
count(): int / isEmpty(): bool 中间件数量 / 是否为空
实现接口 PipelineInterface、MiddlewareInterface、\Countable

中间件适配器(src/Adapter)

类 作用
CallableMiddleware 把 fn($req, $next): Response 包装成 PSR-15 中间件(亦可用 middleware() 函数)
LazyMiddleware 惰性中间件,仅在被实际 process 时才实例化目标(亦可用 lazy() 函数)
ConditionalMiddleware 条件中间件,静态工厂:when(predicate, mw) / unless(predicate, mw) / prefix('/api', mw) / methods(['POST'], mw)

处理器(src/Handler)

类 作用
CallableHandler 把 fn($req): Response 包装成 PSR-15 处理器(亦可用 handler() 函数)
FixedResponseHandler 始终返回固定响应的处理器,常用于兜底 / 短路测试

路由三段式(src/Routing)

类 / 方法 说明
RouteMiddleware 包装一个匹配器闭包(fn($req): RouteResult),把结果写入 kode.route 属性
DispatchMiddleware 读 RouteResult 动态拼子管道,优先级 PHP_INT_MIN 保证最内层
RouteResult::matched($handler, $params, $middleware, $name) 命中
RouteResult::notFound() / methodNotAllowed(array $allowed) 未找到 / 方法不允许
RouteResult::from($request): ?self 从请求读取
isMatched() / isNotFound() / isMethodNotAllowed() / status() 状态判断
handler() / params() / param($k, $d) / middleware() / name() / allowed() 读取元数据
withMiddleware(...) / withHandler($h) 不可变追加 / 替换,返回新实例

优先级约定

数字越大越靠外层(更早进入、更晚退出)。内置中间件默认优先级:

中间件 优先级 位置
ErrorBoundaryMiddleware 2000 最外层异常边界(洋葱兜底,render 失败抛 5002)
ProfilerMiddleware 1500 分层耗时剖析(写 Server-Timing 头)
TraceMiddleware 1000 链路追踪
ScopeMiddleware 900 上下文隔离(依赖 kode/context)
TimeoutMiddleware 850 时间预算
ConcurrentMiddleware 800 注入并发运行器
业务 beforeRoute 0(默认) 路由前
RouteMiddleware 0(默认) 路由匹配
业务 afterRoute 0(默认) 路由后
DispatchMiddleware PHP_INT_MIN 最内层(路由级中间件 + 控制器)

异常边界与可观测性

类 / 方法 说明
ErrorBoundaryMiddleware 优先级 2000,洋葱最外层异常边界;捕获下游 Throwable,按 passthrough 放行、先 reporter 上报再 renderer 渲染;renderer 失效抛 5002
ErrorBoundaryMiddleware::PRIORITY / ATTRIBUTE 2000 / 写入 kode.error 供内层读取
ProfilerMiddleware 优先级 1500,分层耗时剖析;最外层创建 Profile、写 Server-Timing 头,内层复用同一实例形成层级
ProfilerMiddleware::of($req): ?Profile 任意中间件内读取当前 Profile(kode.profile 属性),无全局状态
Profile 耗时收集器:enter($name) / leave($id) / spans() / toServerTiming() / toText(),通过请求属性在洋葱层间传递

应用内核(src/Kernel.php)

Kernel 是框架集成的总入口:洋葱本身只负责「请求进、响应出」,而 Kernel 负责洋葱之外的生命周期——启动、请求 / 响应钩子、最终兜底、收尾。

方法 说明
Kernel::of(PipelineInterface\|Pipe $source) 从管道或构建器创建内核
withBootstrapper(\Closure ...$b) 注册启动回调(进程级,仅一次)
onRequest(\Closure ...$h) / onResponse(\Closure ...$h) 请求改写钩子 / 响应改写钩子(返回 null 表示不改写)
onTerminate(\Closure ...$h) 收尾钩子(响应写回后,异常一律静默)
withExceptionHandler(\Closure $r) 最终兜底(捕获洋葱内任何未处理异常,含最外层中间件自身抛错)
withPipeline(PipelineInterface $p) 替换管道(热更新,无需加锁)
boot(): self 启动(幂等)
handle(ServerRequestInterface): ResponseInterface 处理一次请求(协程安全、可重入)
run(ServerRequestInterface): ResponseInterface handle + terminate(传统 FPM 一体)
terminate(ServerRequestInterface, ResponseInterface): void 收尾(永不抛异常)

所有 withXxx() 配置方法返回新实例,运行期配置不会被意外改写;handle() / terminate() 完全无写入,同一个 Kernel 实例可被 Swoole / Workerman / RoadRunner 的全部 Worker 与协程共享。


框架集成:洋葱模式(Onion after Framework)

Pipeline 负责「洋葱本体」,Kernel 负责「洋葱之外」。二者职责分离,互不替代:

为什么洋葱之外还需要一层?PSR-15 只定义了「请求进、响应出」,但一个真实框架的请求生命周期更长。中间件无法兜住「洋葱最外层中间件自己抛异常」的情况,而内核可以——这是 ErrorBoundaryMiddleware 与 Kernel::withExceptionHandler 构成的双层防线:

完整链路(含「框架洋葱」三段式顺序、控制器异常被边界兜住)由 tests/Unit/OnionTest.php 覆盖。


分组 · 嵌套 · 路由集成(Group · Nest · Router)

「可分组、结合 router、可嵌套」三者其实是同一件事的不同切面:本包用一个机制把它们统一起来——分组名在运行期被解析器展开成一条嵌套子管道。

1. 命名分组(Registry)

分组是一个"中间件别名列表",可引用实例、类名、别名,甚至可以递归引用其它分组:

解析器遇到分组名时会就地展开为嵌套 Pipeline,因此分组内部仍是标准的洋葱嵌套关系。需要构建期确定性摊平(调试、序列化前校验)时,用 Registry::expand()——它带深度上限与环检测,且对合法的菱形依赖(A→B,C;B→D;C→D)不会误报成环:

2. 嵌套组合(Pipe)

Pipeline 自身实现了 MiddlewareInterface,因此天然可作为另一条管道里的一个洋葱层。Pipe 门面提供两种显式写法:

嵌套层对外层完全透明:它有自己的优先级排序,内部请求自外向内、响应自内向外,最内层终点接到主管道的下游处理器。terminate() 收尾会沿嵌套层级自动级联。

3. 路由集成(Router)

Routing\Router 是零依赖的模式路由收集器,把"路径模式 → 处理器 + 路由级中间件"登记起来,并产出 RouteResult 接入 Pipe::router()。路由级中间件可以是命名分组名,经 Pipe 与 DispatchMiddleware 共享的 Resolver 在运行期展开:

Router 支持 {name}([^/]+)与 {name:regex} 占位符、方法约束(不满足方法返回 405)、未命中返回 404。分组 + 路由 + 嵌套在此自然咬合。

4. 路由嵌套分组(Router::group)

路由收集器原生支持带前缀与共享中间件的嵌套分组,闭包内登记的路由会自动带上累积前缀与分组共享中间件(外层 → 内层 → 路由自身):

Pipe::router() 直接接受 Router 实例,无需再包一层 matcher():

5. 一站式路由(Pipe::route / Pipe::routeGroup)

不想先 new Router() 再绑定的话,直接用 Pipe 逐条登记即可——内部惰性创建 Router 并自动绑定路由槽位:

Pipe::group(name, array) 注册的是命名中间件分组(可被路由引用),Pipe::routeGroup(prefix, mw, fn) 做的是路由前缀分组,二者职责不同,请勿混淆。


框架集成桥(Integration\FrameworkBridge)

给 kode 框架一行式接入中间件能力,屏蔽样板代码。框架只需描述业务路由,再把生命周期钩子以关联数组一次性传入,即可拿到可直接 run() 的 {@see Kernel}:

桥默认开启两项便利:

FrameworkBridge::kernel() 与 bridge() 函数完全等价,后者只是命名空间级快捷入口。


代码生成(Codegen)

Codegen\MiddlewareGenerator 把"类名 / 优先级 / 描述"确定性地渲染成符合本包约定的 PSR-15 中间件源码,不依赖任何模板引擎,可无缝接入脚手架与 middleware-assistant 技能:

生成的类满足:declare(strict_types=1)、实现 Psr\Http\Server\MiddlewareInterface、暴露 public const PRIORITY(供 Pipeline 自动取用优先级)、process() 内给出"调用下游之前 / 响应返回之前"两处织入点注释。类名非法(含路径穿越字符)会抛 RuntimeException。


并发:多进程 / 多线程 / Fiber 协程

运行器自动降级

RunnerFactory 保证任何情况下都能返回一个可用的运行器,最差也是 SyncRunner。业务代码永远不需要写 if (extension_loaded('parallel')) 这类分支:

驱动(DRIVER_*) 运行器 需要
auto(默认) 按 profile 自动选 —
sync SyncRunner 无
fiber FiberRunner kode/fibers(或原生 \Fiber)
thread ThreadRunner ext-parallel + kode/parallel
process ProcessRunner kode/process

*自动挑选策略(driver = auto)按任务画像(`PROFILE_`)区分:**

RunnerInterface 统一方法:run($task) / all(array $tasks, ?float $timeout) / supported(): bool / close(): void。

在控制器里并发

通过 ConcurrentMiddleware 把运行器注入请求属性,下游直接取用:

相关类:ConcurrentMiddleware(优先级 800,ATTRIBUTE = kode.runner,静态 runnerOf($req))、TimeoutMiddleware(优先级 850,deadline propagation,ON_TIMEOUT_HEADER / ON_TIMEOUT_THROW 策略,静态 remaining($req, $default))、ScopeMiddleware(优先级 900,依赖 kode/context 做上下文隔离)。


分布式:链路追踪与节点标识

链路以 W3C Trace Context(traceparent 头)为基准,可直接被 Jaeger / SkyWalking / OTel Collector 识别。

类 / 方法 说明
TraceMiddleware 优先级 1000;从 traceparent 取 / 建链路,写入 kode.trace 属性与 kode/context;响应头回写 X-Trace-Id / X-Request-Id / X-Node-Id / X-Duration-Ms。静态 contextOf($req) / traceIdOf($req)
Propagator extract($req) 入站解析、inject($ctx) 出站头、forward($req) 便捷组合、parseTraceparent($h)、HEADER_TRACEPARENT / HEADER_REQUEST_ID / HEADER_NODE_ID 常量
NodeIdentity 节点 ID 解析优先级:构造参数 → KODE_NODE_ID → HOSTNAME → gethostname() → unknown;id() / pid() / instance()(web-01#12345 形式)

注册表与别名(Registry)

让管道用短字符串书写。Registry 在构建期可变,管道运行期不可变,二者职责分离。

方法 说明
alias($name, $mw) / aliases(array $map) 注册单个别名 / 批量
group($name, array $mw) 注册分组(解析时展开为子管道)
factory($name, \Closure $f) 注册带参工厂
has($name) / lookup($name) 是否注册 / 查声明(名称:参数 语法)
allAliases() / allGroups() 导出(供 Blueprint 序列化)
mergeFrom(Registry $other) 合并(同名以传入者为准)

蓝图:跨进程 / 跨节点下发(Blueprint)

管道对象本身无法跨边界传输(闭包不可序列化、实例常持有连接等资源)。Blueprint 只保留「名字」——中间件类名与注册表别名——可 json_encode 后写入配置中心、随任务投递到 ext-parallel 线程、通过 IPC 发给 kode/process 子进程或下发集群其它节点;对端用本地容器 rebuild() 出等价管道。

方法 说明
Blueprint::fromPipe(array $before, array $after, ?Registry $r) 从 Pipe 声明提取(仅保留字符串声明)
Blueprint::fromArray(array $data) / fromJson(string $json) 从数组 / JSON 还原
rebuild(?ContainerInterface $c, ?Registry $r): Pipeline 重建管道
rebuildPipe(?ContainerInterface $c): Pipe 重建 Pipe(保留分段信息,便于补本地路由匹配器)
toArray() / toJson($flags) / jsonSerialize() 序列化
fingerprint(): string MD5 摘要,用于比对各节点编排是否一致
VERSION 常量 蓝图格式版本('1')

与其他 kode 包集成

包 关系
kode/http 提供 PSR-7 消息实现与 HTTP 服务端;本包是它底层管道的可重入升级底座。业务中间件(CORS / 限流 / 鉴权)建议在 kode/http 或你的业务层实现,本包只负责编排与执行。
kode/context TraceMiddleware / ScopeMiddleware 把链路 ID、请求上下文写入 kode/context,在 Fiber / 协程 / 线程 / 进程四种模型下正确隔离、不串号。
kode/di 作为 PSR-11 容器注入 Pipe / Resolver,按类名解析并自动装配中间件构造函数。
kode/fibers FiberRunner 的底层协程引擎。
kode/parallel ThreadRunner 的底层多线程引擎(ext-parallel)。
kode/process ProcessRunner 的底层多进程引擎。

以上均为 composer.json 中的 suggest 软依赖,未安装时对应能力自动降级,不影响核心管道运行。


兼容性

维度 支持情况
PHP 8.3+(用到 readonly、枚举、\Fiber、稳定排序等特性)
运行模式 FPM / CLI / Swoole / Workerman / RoadRunner 均可(管道本身与运行模式无关)
并发模型 同步、Fiber 协程、ext-parallel 多线程、kode/process 多进程
PSR 兼容 PSR-7、PSR-11、PSR-15、PSR-17(消息实现由外部提供)
序列化下发 Blueprint(JSON)跨进程 / 跨线程 / 跨节点

设计要点:为什么能「协程安全、可重入、可重试」

常见的 MiddlewarePipeline(如 kode/http 早期实现)会在调度器上保存一个可变的 private int $index,靠自增推进管道。这有三个致命缺陷:

  1. 不可重入:同一调度器处理第二个请求时,index 已停在末尾;
  2. 协程不安全:Fiber / Swoole 协程交错时,两个请求会互相推进对方的游标,导致「串号」;
  3. 无法重试:中间件想对下游做一次重试(两次调用 $handler->handle())时,第二次会从错误位置继续。

本包改用 不可变游标 Cursor:每前进一步就构造一个 index+1 的新游标对象,自身状态构造后永不改变。于是管道对象在处理期间零写入,可并发共享、可重入、可重试,且可安全地跨 Worker 复用。


测试

当前测试覆盖(95 tests / 187 assertions):管道不可变 / 可重入 / 协程交错不串号 / 可重试、Resolver 惰性 / 别名 / 分组 / 带参工厂 / 容器 / 条件 / 错误码、路由三段式顺序与兜底、Kernel 启动幂等 · 钩子 · 兜底 · 收尾级联 · Fiber 可重入、循环引用防护 / 惰性收尾级联 / 蓝图白名单等健壮性、异常边界 · 分层剖析 · 完整框架洋葱链路,以及分组递归展开 / Router 路由收集器 / Pipe 嵌套组合 / 路由引用命名分组 / Codegen 代码生成等能力;本轮新增 Router 嵌套分组前缀与中间件累积、 Pipe::router(Router) 直接接入、 Pipe::route / routeGroup 一站式登记、 FrameworkBridge 框架集成桥(stack / observe / 一行式内核) 的集成测试。

许可证

MIT


All versions of middleware with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
psr/container Version ^1.1 || ^2.0
psr/http-message Version ^1.1 || ^2.0
psr/http-server-handler Version ^1.0
psr/http-server-middleware Version ^1.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package kode/middleware contains the following files

Loading the files please wait ...