使用Zend View并运行在swoole http服务器上的Zend表现力应用程序面临着一种奇怪的行为。这种行为与单例模式有关。
我们已经将Zend表达式配置为在swoole http服务器( https://docs.zendframework.com/zend-expressive-swoole/ )中运行,并且所有apis编程都没有问题(swoole是一个火箭!)
但是我们已经尝试进入下一个步骤,并且尝试通过swoole http服务器执行一个web接口。
在那里,我们发现了奇怪的行为。为了简化我的问题(我们使用了很多视图助手),我们的web界面使用Zend并使用headTitle助手。当您第一次加载web界面时,一切正常,但是当您重新加载页面时,您可以看到元标题是重复的。
下一个是我们的处理程序
public function handle(ServerRequestInterface $request) : ResponseInterface
{
$data = [
"rand" => rand(1000, 9999),
"time" => date("Y-m-d H:i:s")
];
return new HtmlResponse($this->template->render('app::my-view', $data));
}我们的看法是下一个
<?php $this->headTitle('My Page'); ?>
<b>Rand</b>: <?php echo $rand; ?><br>
<b>Time</b>: <?php echo $time; ?><br>
<hr>在谷歌搜索中,我们在https://framework.zend.com/blog/2018-03-21-expressive-swoole.html上发现Zend的团队也面临着类似的问题:
但是,对于异步服务器,每个请求都将使用相同的实例。通常,对PSR-7消息实例的操作将创建新的实例,因为它们实现的接口被指定为不可变。不幸的是,由于PHP语言的技术限制,我们无法使响应消息不可变。这意味着,如果一个进程写入该主体,那么随后的进程--甚至是并行执行的进程--将收到相同的更改。这可能导致,在最好的情况下,重复的内容,在最坏的情况下,提供不正确的内容或执行信息泄漏!
他们解决了这个问题
为了解决这些问题,我们修改了Psr\Http\Message\ResponseInterface服务,注册到依赖注入容器:它现在返回的不是接口的实例,而是能够生成实例的工厂。
但是,检查Zend类,我们发现了另一个问题,因为解决方案是在代码中实现的,所有对apis的请求都是正确的
在zend-expressive/src/ConfigProvider.php中,您可以看到
ServerRequestInterface::class => ServerRequestSwooleFactory::class,然后,我们改变我们的观点,检查zend视图帮助程序,我们发现视图助手HeadTitle从容器\抽象标准扩展
file: zend-view/src/Helper/HeadTitle
class HeadTitle extends Placeholder\Container\AbstractStandalone在这个AbstractStandalone中,我们发现在构造函数方法中,容器是通过一个单例加载的。
file: zend-view/src/Helper/Placeholder\Container\AbstractStandalone
public function getContainer()
{
if (! $this->container instanceof AbstractContainer) {
$this->container = new $this->containerClass();
}
return $this->container;
}这就是问题所在。使用模块,每个请求和每个响应都是独立的,但是同一个Singleton容器被一次又一次地使用。
你面对过这个问题吗?你是怎么解决的?
我们正在考虑创建一个自定义助手来删除所有的视图助手容器,但是如果我们这样做了,我们必须更改很多视图文件来添加这个新的和自定义的助手。
提前感谢
发布于 2018-09-26 13:27:30
我向https://github.com/zendframework/zend-expressive-swoole/issues/34中的库开发团队提出了这个问题,他们向我展示了一种方法:
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$layout = clone $this->layout;
$this->phpRenderer->viewModel()->setRoot($layout);
$this->phpRenderer->headTitle()->deleteContainer();
$this->phpRenderer->headMeta()->deleteContainer();
$this->phpRenderer->seo()->reset();
}https://stackoverflow.com/questions/52441578
复制相似问题