1

Zend View を使用し、swoole http サーバーで実行されている Zend Expressive アプリケーションで奇妙な動作に直面しています。この動作は Singleton パターンに関連しています。

Zend Expressive を swoole http サーバー ( https://docs.zendframework.com/zend-expressive-swoole/ ) で実行するように構成し、プログラムされたすべての API は問題なく動作します (swoole はロケットです!)。

しかし、次のステップに進み、swoole http サーバーを介して Web インターフェイスを実行しようとしました。

そこで、奇妙な動作を発見しました。私の質問を簡単にするために (私たちは多くのビュー ヘルパーを使用しています)、私たちの Web インターフェイスは Zend View と連携し、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>

Google で検索したところ、https://framework.zend.com/blog/2018-03-21-expressive-swoole.htmlで、Zend のチームが同様の問題に直面していたことがわかりました。

ただし、非同期サーバーでは、すべてのリクエストで同じインスタンスが使用されます。通常、PSR-7 メッセージ インスタンスを操作すると、それらが実装するインターフェイスが不変として指定されているため、新しいインスタンスが作成されます。残念ながら、PHP 言語の技術的な制限により、応答メッセージの本文を不変にすることはできませんでした。これは、1 つのプロセスがその本体に書き込みを行うと、後続のプロセス、または並行して実行されているプロセスでさえも実行されることを意味します。— 同じ変更を受け取ります。これは、最良のシナリオではコンテンツの複製につながり、最悪の場合、誤ったコンテンツを提供したり、情報漏えいを実行したりする可能性があります!

そして、彼らはそれを解決しました

これらの状況に対処するために、依存性注入コンテナーに登録する Psr\Http\Message\ResponseInterface サービスを変更しました。これは、インターフェイスのインスタンスではなく、インスタンスを生成できるファクトリを返すようになりました。

しかし、Zend Framework クラスを調べると、別の問題があることがわかりました。これは、ソリューションがコードに実装されており、API に対して行われたすべてのリクエストが正しかったためです。

zend-expressive-swoole/src/ConfigProvider.php で確認できます

ServerRequestInterface::class         => ServerRequestSwooleFactory::class,

次に、視点を変更して zend ビュー ヘルパーを調べたところ、ビュー ヘルパーの HeadTitle が Container\AbstractStandalone から拡張されていることがわかりました。

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;
}

これが問題です。Zend Expressive Swoole モジュールでは、すべてのリクエストとすべてのレスポンスが独立していますが、同じシングルトン コンテナーが何度も使用されます。

この問題に直面したことがありますか?これをどのように解決しましたか?

すべてのビュー ヘルパー コンテナーを削除するカスタム ヘルパーを作成することを考えていますが、そうすると、この新しいカスタム ヘルパーを追加するために多くのビュー ファイルを変更する必要があります。

前もって感謝します

4

1 に答える 1