为什么容器 运行 在中间件之前?
Why does a container run before middleware?
如果我们查看发布在 slim4 website 和其他地方的中间件概念。
应在请求到达应用程序之前或向用户发送响应时执行。
问题是这样的,因为即使之前执行了一个中间件,应用程序之前调用了一个容器:
显示代码。
配置
'providers' => [,
App\ServiceProviders\Flash::class => 'http'
],
'middleware' => [
App\Middleware\Session::class => 'http,console',
],
会话中间件
class Session
{
public function __invoke(Request $request, RequestHandler $handler)
{
if (session_status() !== PHP_SESSION_ACTIVE) {
$settings = app()->getConfig('settings.session');
if (!is_dir($settings['filesPath'])) {
mkdir($settings['filesPath'], 0777, true);
}
$current = session_get_cookie_params();
$lifetime = (int)($settings['lifetime'] ?: $current['lifetime']);
$path = $settings['path'] ?: $current['path'];
$domain = $settings['domain'] ?: $current['domain'];
$secure = (bool)$settings['secure'];
$httponly = (bool)$settings['httponly'];
session_save_path($settings['filesPath']);
session_set_cookie_params($lifetime, $path, $domain, $secure, $httponly);
session_name($settings['name']);
session_cache_limiter($settings['cache_limiter']);
session_start();
}
return $handler->handle($request);
}
}
Flash 消息容器
class Flash implements ProviderInterface
{
public static function register()
{
$flash = new Messages();
return app()->getContainer()->set(Messages::class, $flash);
}
}
执行应用程序
...
// Instantiate PHP-DI ContainerBuilder
$containerBuilder = new ContainerBuilder();
AppFactory::setContainer($containerBuilder->build());
$app = AppFactory::create();
$providers = (array)$this->getConfig('providers');
array_walk($providers, function ($appName, $provider) {
if (strpos($appName, $this->appType) !== false) {
/** @var $provider ProviderInterface */
$provider::register();
}
});
$middlewares = array_reverse((array)$this->getConfig('middleware'));
array_walk($middlewares, function ($appType, $middleware) {
if (strpos($appType, $this->appType) !== false) {
$this->app->add(new $middleware);
}
});
....
$app->run();
结果
`Fatal error: Uncaught RuntimeException: Flash messages middleware failed. Session not found.`
Flash 消息需要一个会话开始工作我已经知道了,中间件应该负责做这件事,但它总是在容器之后执行
首先,您使用的 dependency
和 container
术语好像它们是同一事物,但实际上它们不是。
关于您的代码问题,在 Flash::register()
方法中,您正在从 Messages
class 创建一个新对象并将其放入在 DI 容器中。您正在调用此方法并强制创建 Message 对象,这需要会话已经启动,before 让中间件启动会话。你真的应该避免在 DIC 中存储对象,而不是存储它们的定义(它们是如何构建的)。以下更改是我的意思:
class Flash implements ProviderInterface
{
public static function register()
{
return app()->getContainer()->set(Messages::class, function() {
return new Messages();
});
}
}
如果我们查看发布在 slim4 website 和其他地方的中间件概念。
应在请求到达应用程序之前或向用户发送响应时执行。
问题是这样的,因为即使之前执行了一个中间件,应用程序之前调用了一个容器:
显示代码。
配置
'providers' => [,
App\ServiceProviders\Flash::class => 'http'
],
'middleware' => [
App\Middleware\Session::class => 'http,console',
],
会话中间件
class Session
{
public function __invoke(Request $request, RequestHandler $handler)
{
if (session_status() !== PHP_SESSION_ACTIVE) {
$settings = app()->getConfig('settings.session');
if (!is_dir($settings['filesPath'])) {
mkdir($settings['filesPath'], 0777, true);
}
$current = session_get_cookie_params();
$lifetime = (int)($settings['lifetime'] ?: $current['lifetime']);
$path = $settings['path'] ?: $current['path'];
$domain = $settings['domain'] ?: $current['domain'];
$secure = (bool)$settings['secure'];
$httponly = (bool)$settings['httponly'];
session_save_path($settings['filesPath']);
session_set_cookie_params($lifetime, $path, $domain, $secure, $httponly);
session_name($settings['name']);
session_cache_limiter($settings['cache_limiter']);
session_start();
}
return $handler->handle($request);
}
}
Flash 消息容器
class Flash implements ProviderInterface
{
public static function register()
{
$flash = new Messages();
return app()->getContainer()->set(Messages::class, $flash);
}
}
执行应用程序
...
// Instantiate PHP-DI ContainerBuilder
$containerBuilder = new ContainerBuilder();
AppFactory::setContainer($containerBuilder->build());
$app = AppFactory::create();
$providers = (array)$this->getConfig('providers');
array_walk($providers, function ($appName, $provider) {
if (strpos($appName, $this->appType) !== false) {
/** @var $provider ProviderInterface */
$provider::register();
}
});
$middlewares = array_reverse((array)$this->getConfig('middleware'));
array_walk($middlewares, function ($appType, $middleware) {
if (strpos($appType, $this->appType) !== false) {
$this->app->add(new $middleware);
}
});
....
$app->run();
结果
`Fatal error: Uncaught RuntimeException: Flash messages middleware failed. Session not found.`
Flash 消息需要一个会话开始工作我已经知道了,中间件应该负责做这件事,但它总是在容器之后执行
首先,您使用的 dependency
和 container
术语好像它们是同一事物,但实际上它们不是。
关于您的代码问题,在 Flash::register()
方法中,您正在从 Messages
class 创建一个新对象并将其放入在 DI 容器中。您正在调用此方法并强制创建 Message 对象,这需要会话已经启动,before 让中间件启动会话。你真的应该避免在 DIC 中存储对象,而不是存储它们的定义(它们是如何构建的)。以下更改是我的意思:
class Flash implements ProviderInterface
{
public static function register()
{
return app()->getContainer()->set(Messages::class, function() {
return new Messages();
});
}
}