VSlimContainer
VSlim\Container
VSlim\Container 是 VSlim 内置的 PSR-11 容器实现。它来自 vslim.so,不是用户态 PHP 写出来的 mock。
真理之源:
src/container.vtests/test_vslim_container_psr11_ext.phpttests/test_vslim_container_route_handler.phpt
依赖
如果要使用 PSR-11 接口,需要 psr 扩展中的这些接口存在:
Psr\Container\ContainerInterfacePsr\Container\NotFoundExceptionInterfacePsr\Container\ContainerExceptionInterface
基本用法
$c = new VSlim\Container();
$c->set('name', 'codex');
$c->factory('hello', fn () => 'hi-' . $c->get('name'));
echo $c->get('name') . PHP_EOL;
echo $c->get('hello') . PHP_EOL;
API
set($id, $value)factory($id, $callable)has($id)get($id)
set()
注册一个固定值:
$c->set(FooService::class, new FooService());
factory()
注册一个工厂:
$c->factory('clock', fn () => new DateTimeImmutable('now'));
当前实现会缓存 factory 的解析结果,所以同一个 id 多次 get() 会得到第一次创建出来的对象/值。
异常
容器内置两个异常类:
VSlim\Container\ContainerExceptionVSlim\Container\NotFoundException
找不到条目时会抛:
try {
$c->get('missing');
} catch (VSlim\Container\NotFoundException $e) {
// ...
}
和 VSlim\App 的关系
App 有两个入口:
container()set_container()
最常见:
$app = new VSlim\App();
$container = $app->container();
App 第一次调用 container() 时会自动创建一个容器实例。
Route handler 如何从容器解析
VSlim 路由不仅接受闭包,也接受容器服务 id 或数组形式的 handler。
1. 字符串 service id
$container->set('hello.handler', function (VSlim\Request $req) {
return 'hello:' . $req->param('id');
});
$app->get('/hello/:id', 'hello.handler');
2. [service, method]
$container->set('users.controller', new UserController());
$app->get('/users/:id', ['users.controller', 'show']);
3. [service]
如果 service 对象可调用或带 __invoke(),可以省略方法名:
$container->set('invoke.controller', new InvokableController());
$app->get('/inv/:id', ['invoke.controller']);
4. 自动类名解析
如果容器里没有这个 service id,但这个字符串本身是一个存在的类名,VSlim 会尝试自动实例化并放入容器:
$app->get('/auto/:id', AutoController::class);
$app->get('/auto-show/:id', [AutoController::class, 'show']);
这要求类可无参构造。
注意事项
factory()参数必须是 callable,否则抛ContainerException- 自动类名解析只在路由 handler 解析阶段触发
- 对路由来说,字符串和数组 handler 都依赖容器