<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sergii Dolgushev</title>
    <description>The latest articles on DEV Community by Sergii Dolgushev (@sergiid).</description>
    <link>https://dev.to/sergiid</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1325057%2Fd15b19ab-9d92-4c8c-8017-a25ac0781eab.jpeg</url>
      <title>DEV Community: Sergii Dolgushev</title>
      <link>https://dev.to/sergiid</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sergiid"/>
    <language>en</language>
    <item>
      <title>Getting Symfony app ready for Swoole, RoadRunner, and FrankenPHP (no AI involved)</title>
      <dc:creator>Sergii Dolgushev</dc:creator>
      <pubDate>Mon, 04 Mar 2024 14:01:53 +0000</pubDate>
      <link>https://dev.to/sergiid/getting-symfony-app-ready-for-swoole-roadrunner-and-frankenphp-no-ai-involved-2d0g</link>
      <guid>https://dev.to/sergiid/getting-symfony-app-ready-for-swoole-roadrunner-and-frankenphp-no-ai-involved-2d0g</guid>
      <description>&lt;p&gt;Greetings dear reader! It has been a while since I wrote last time, so it is very nice to see you! And I hope this post will be interesting, and you find something fresh in it. On this note, I need to warn you: if you are familiar with the &lt;a href="https://en.wikipedia.org/wiki/Shared_memory" rel="noopener noreferrer"&gt;Shared Memory Model&lt;/a&gt; that is introduced by &lt;a href="https://github.com/swoole/swoole-src" rel="noopener noreferrer"&gt;Swoole&lt;/a&gt;, and &lt;a href="https://roadrunner.dev/" rel="noopener noreferrer"&gt;RoadRunner&lt;/a&gt;, &lt;a href="https://frankenphp.dev/" rel="noopener noreferrer"&gt;FrankenPHP&lt;/a&gt; and you are 100% certain that all the services in your codebase are stateless, you might skip reading further. Otherwise, welcome!&lt;/p&gt;

&lt;p&gt;I will use a simple &lt;a href="https://symfony.com/" rel="noopener noreferrer"&gt;Symfony 7.0&lt;/a&gt; application in this post, but all the concepts apply to any PHP codebase.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Shared Nothing Model
&lt;/h3&gt;

&lt;p&gt;Usually, the &lt;a href="https://www.php.net/manual/en/install.fpm.php" rel="noopener noreferrer"&gt;PHP-FPM (FastCGI Process Manager)&lt;/a&gt; takes all requests for the PHP application and distributes them to individual PHP processes, also called workers. Each worker handles one request in a time. So the more workers are running, the more requests in parallel can be handled. In this case &lt;a href="https://en.wikipedia.org/wiki/Shared-nothing_architecture" rel="noopener noreferrer"&gt;Shared Nothing Model&lt;/a&gt; is implemented by running the garbage collector to clear the memory between the requests (within the same worker). So no memory is shared between the requests:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndc0cbc2919t4t2vznnr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndc0cbc2919t4t2vznnr.png" alt="Shared Nothing Model" width="501" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is nothing special about it, and it is how PHP applications have been running for a while.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared Memory Model
&lt;/h3&gt;

&lt;p&gt;But it changes after &lt;a href="https://github.com/swoole/swoole-src" rel="noopener noreferrer"&gt;Swoole&lt;/a&gt; / &lt;a href="https://roadrunner.dev/" rel="noopener noreferrer"&gt;RoadRunner&lt;/a&gt; / &lt;a href="https://frankenphp.dev/docs/worker/" rel="noopener noreferrer"&gt;FrankenPHP (Worker Mode)&lt;/a&gt; is used. All of them use &lt;a href="https://en.wikipedia.org/wiki/Shared_memory" rel="noopener noreferrer"&gt;Shared Memory Model&lt;/a&gt;, which gives its power:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqjk6l1thah8f4uidq9h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqjk6l1thah8f4uidq9h.png" alt="Shared Memory Model" width="501" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So within the same worker, the memory is shared to handle different requests. It leads to performance improvements, but in the same way, it might lead to some unexpected side effects, that are hard to notice and debug. Let's demonstrate the simplest way to reproduce it. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to reproduce
&lt;/h2&gt;

&lt;p&gt;We will use &lt;a href="https://github.com/SerheyDolgushev/php-shared-memory-model" rel="noopener noreferrer"&gt;php-shared-memory-model&lt;/a&gt; repository to showcase unexpected side effects caused by the &lt;a href="https://en.wikipedia.org/wiki/Shared_memory" rel="noopener noreferrer"&gt;Shared Memory Model&lt;/a&gt;. It contains a single &lt;a href="https://github.com/SerheyDolgushev/php-shared-memory-model/blob/51dc506ebd987a42acc521476dbe46e06b87cc25/src/Controller/TestController.php" rel="noopener noreferrer"&gt;TestController&lt;/a&gt; controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Bundle\FrameworkBundle\Controller\AbstractController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\HttpFoundation\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\HttpFoundation\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\Routing\Annotation\Route&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="na"&gt;#[Route(path: '/test', name: 'test', methods: [Request::METHOD_GET])]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testAction&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'['&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;\date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'c'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'] Counter: '&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_OK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'text/html'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And is quite simple to install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/Projects
git clone git@github.com:SerheyDolgushev/php-shared-memory-model.git
&lt;span class="nb"&gt;cd &lt;/span&gt;php-shared-memory-model
composer &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's run it using local PHP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-S&lt;/span&gt; 127.0.0.1:8000 public/index.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And send a few test requests to the test controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% curl http://127.0.0.1:8000/test
&lt;span class="o"&gt;[&lt;/span&gt;2024-02-24T08:05:03+00:00] Counter: 1
% curl http://127.0.0.1:8000/test
&lt;span class="o"&gt;[&lt;/span&gt;2024-02-24T08:05:07+00:00] Counter: 1
% curl http://127.0.0.1:8000/test
&lt;span class="o"&gt;[&lt;/span&gt;2024-02-24T08:05:10+00:00] Counter: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing surprising at this point, all the responses return the expected counter. &lt;/p&gt;

&lt;p&gt;Now let's follow additional installation instructions for &lt;a href="https://github.com/SerheyDolgushev/php-shared-memory-model/tree/main?tab=readme-ov-file#swoole" rel="noopener noreferrer"&gt;Swoole&lt;/a&gt;, &lt;a href="https://github.com/SerheyDolgushev/php-shared-memory-model/tree/main?tab=readme-ov-file#roadrunner" rel="noopener noreferrer"&gt;RoadRunner&lt;/a&gt;, and &lt;a href="https://github.com/SerheyDolgushev/php-shared-memory-model/tree/main?tab=readme-ov-file#frankenphp" rel="noopener noreferrer"&gt;FrankenPHP&lt;/a&gt;, and run test the same controller in any of those runtimes (Swoole is used in this example):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;APP_RUNTIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Runtime&lt;span class="se"&gt;\\&lt;/span&gt;Swoole&lt;span class="se"&gt;\\&lt;/span&gt;Runtime php &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;extension&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;swoole.so public/swoole.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% curl http://127.0.0.1:8000/test
&lt;span class="o"&gt;[&lt;/span&gt;2024-02-24T08:07:59+00:00] Counter: 1
% curl http://127.0.0.1:8000/test
&lt;span class="o"&gt;[&lt;/span&gt;2024-02-24T08:08:02+00:00] Counter: 2
% curl http://127.0.0.1:8000/test
&lt;span class="o"&gt;[&lt;/span&gt;2024-02-24T08:08:06+00:00] Counter: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the counter value increased for each response, which is explained by the Shared Memory Model, but might be unexpected in some cases. And it definitely needs to be fixed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to fix
&lt;/h2&gt;

&lt;p&gt;At this point, it is clear that all the services need to be stateless, otherwise in some cases the app might behave in the unexpected way. In order to make sure all the services in our app are stateless we can manually check them. Which can be acceptable in smaller projects, but is very tedious in larger codebases. There should be a simpler way to do it, right? &lt;/p&gt;

&lt;p&gt;I feel now is the perfect moment to introduce the tool I have been working during the last few weekends. Ladies and gentlemen, please meet &lt;a href="https://github.com/denzyldick/phanalist" rel="noopener noreferrer"&gt;phanalist&lt;/a&gt;. It is a static analyzer for PHP projects, that is written in RUST. It is extremely easy to use: you just download compiled binary for your platform and run it (no PHP runtime is required). It comes with  &lt;a href="https://github.com/denzyldick/phanalist?tab=readme-ov-file#rules" rel="noopener noreferrer"&gt;some useful rules&lt;/a&gt;, but we will be focused on &lt;a href="https://github.com/denzyldick/phanalist/tree/27b18ec0292a79d57d29835f95d2ecaacf921ba7/src/rules/examples/e12" rel="noopener noreferrer"&gt;E0012&lt;/a&gt;. As this is the rule that checks if services are stateless.&lt;/p&gt;

&lt;p&gt;Let's &lt;a href="https://github.com/denzyldick/phanalist/tree/main?tab=readme-ov-file#installation" rel="noopener noreferrer"&gt;install phanalist&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://raw.githubusercontent.com/denzyldick/phanalist/main/bin/init.sh | sh

info: Downloading https://raw.githubusercontent.com/denzyldick/phanalist/main/release/aarch64-apple-darwin/phanalist ...
info: Saved /Users/sergiid/phanalist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And run it only against &lt;code&gt;E0012&lt;/code&gt; rule, checking &lt;code&gt;./src&lt;/code&gt; path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% ~/phanalist &lt;span class="nt"&gt;-r&lt;/span&gt; E0012 &lt;span class="nt"&gt;-s&lt;/span&gt; ./src
The new ./phanalist.yaml configuration file as been created

Scanning files &lt;span class="k"&gt;in&lt;/span&gt; ./src ...
██████████████████████████████████████████████████████████ 4/4
./src/Controller/TestController.php, detected 1 violations:
  E0012:    Setting service properties leads to issues with Shared Memory Model &lt;span class="o"&gt;(&lt;/span&gt;FrankenPHP/Swoole/RoadRunner&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; Trying to &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;-&amp;gt;counter property
  19:52 |         &lt;span class="nv"&gt;$content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'['&lt;/span&gt;.&lt;span class="se"&gt;\d&lt;/span&gt;ate&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'c'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.&lt;span class="s1"&gt;'] Counter: '&lt;/span&gt;.&lt;span class="o"&gt;(&lt;/span&gt;++&lt;span class="nv"&gt;$this&lt;/span&gt;-&amp;gt;counter&lt;span class="o"&gt;)&lt;/span&gt;.PHP_EOL&lt;span class="p"&gt;;&lt;/span&gt;

+-----------+------------------------------------------------+------------+
| Rule Code | Description                                    | Violations |
+-----------+------------------------------------------------+------------+
| E0012     | Service compatibility with Shared Memory Model |          1 |
+-----------+------------------------------------------------+------------+

Analysed 2 files &lt;span class="k"&gt;in &lt;/span&gt;2.30ms, memory usage: 4.6 MiB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the first run &lt;code&gt;./phanalist.yaml&lt;/code&gt; will be created. And depending on your project, you might want to adjust configurations for &lt;code&gt;E0012&lt;/code&gt; rule.&lt;/p&gt;

&lt;p&gt;Most likely, you will get a different output for your project. But it will contain all the stateful services, that need to be converted to stateless.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to fix
&lt;/h2&gt;

&lt;p&gt;Converting a list of services to stateless might be not such an easy task, especially if there are a lot of services that you are not familiar with. Manually modifying the code that sets the state for the service might be very challenging, because of myriad of reasons: you might not be aware of all the use cases for the service/it might be a legacy code that is hard to understand/you name it. And again, there should be a better approach to handle it, right?&lt;/p&gt;

&lt;p&gt;The good news is that there is a better and simpler way to do it: Symfony provides a &lt;a href="https://github.com/symfony/symfony/blob/7.0/src/Symfony/Contracts/Service/ResetInterface.php" rel="noopener noreferrer"&gt;ResetInterface&lt;/a&gt; interface, that is designed to be used exactly in cases like this. Hopefully, other frameworks have something similar.&lt;/p&gt;

&lt;p&gt;So now we need just to apply &lt;a href="https://github.com/symfony/symfony/blob/7.0/src/Symfony/Contracts/Service/ResetInterface.php" rel="noopener noreferrer"&gt;ResetInterface&lt;/a&gt; for each stateful service. So &lt;a href="https://github.com/SerheyDolgushev/php-shared-memory-model/blob/51dc506ebd987a42acc521476dbe46e06b87cc25/src/Controller/TestController.php" rel="noopener noreferrer"&gt;TestController&lt;/a&gt; will become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% git diff src/Controller/TestController.php
diff &lt;span class="nt"&gt;--git&lt;/span&gt; a/src/Controller/TestController.php b/src/Controller/TestController.php
index 82b06b3..e01962c 100644
&lt;span class="nt"&gt;---&lt;/span&gt; a/src/Controller/TestController.php
+++ b/src/Controller/TestController.php
@@ &lt;span class="nt"&gt;-8&lt;/span&gt;,8 +8,9 @@ use Symfony&lt;span class="se"&gt;\B&lt;/span&gt;undle&lt;span class="se"&gt;\F&lt;/span&gt;rameworkBundle&lt;span class="se"&gt;\C&lt;/span&gt;ontroller&lt;span class="se"&gt;\A&lt;/span&gt;bstractController&lt;span class="p"&gt;;&lt;/span&gt;
 use Symfony&lt;span class="se"&gt;\C&lt;/span&gt;omponent&lt;span class="se"&gt;\H&lt;/span&gt;ttpFoundation&lt;span class="se"&gt;\R&lt;/span&gt;equest&lt;span class="p"&gt;;&lt;/span&gt;
 use Symfony&lt;span class="se"&gt;\C&lt;/span&gt;omponent&lt;span class="se"&gt;\H&lt;/span&gt;ttpFoundation&lt;span class="se"&gt;\R&lt;/span&gt;esponse&lt;span class="p"&gt;;&lt;/span&gt;
 use Symfony&lt;span class="se"&gt;\C&lt;/span&gt;omponent&lt;span class="se"&gt;\R&lt;/span&gt;outing&lt;span class="se"&gt;\A&lt;/span&gt;nnotation&lt;span class="se"&gt;\R&lt;/span&gt;oute&lt;span class="p"&gt;;&lt;/span&gt;
+use Symfony&lt;span class="se"&gt;\C&lt;/span&gt;ontracts&lt;span class="se"&gt;\S&lt;/span&gt;ervice&lt;span class="se"&gt;\R&lt;/span&gt;esetInterface&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nt"&gt;-class&lt;/span&gt; TestController extends AbstractController
+class TestController extends AbstractController implements ResetInterface
 &lt;span class="o"&gt;{&lt;/span&gt;
     private int &lt;span class="nv"&gt;$counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 0&lt;span class="p"&gt;;&lt;/span&gt;

@@ &lt;span class="nt"&gt;-20&lt;/span&gt;,4 +21,9 @@ class TestController extends AbstractController

         &lt;span class="k"&gt;return &lt;/span&gt;new Response&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$content&lt;/span&gt;, Response::HTTP_OK, &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'text/html'&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="o"&gt;}&lt;/span&gt;
+
+    public &lt;span class="k"&gt;function &lt;/span&gt;reset&lt;span class="o"&gt;()&lt;/span&gt;
+    &lt;span class="o"&gt;{&lt;/span&gt;
+        &lt;span class="nv"&gt;$this&lt;/span&gt;-&amp;gt;counter &lt;span class="o"&gt;=&lt;/span&gt; 0&lt;span class="p"&gt;;&lt;/span&gt;
+    &lt;span class="o"&gt;}&lt;/span&gt;
 &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's restart Swoole runtime after this change&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;APP_RUNTIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Runtime&lt;span class="se"&gt;\\&lt;/span&gt;Swoole&lt;span class="se"&gt;\\&lt;/span&gt;Runtime php &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;extension&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;swoole.so public/swoole.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And send a few test requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% curl http://127.0.0.1:8000/test
&lt;span class="o"&gt;[&lt;/span&gt;2024-03-04T09:37:29+00:00] Counter: 1
% curl http://127.0.0.1:8000/test
&lt;span class="o"&gt;[&lt;/span&gt;2024-03-04T09:37:30+00:00] Counter: 1
% curl http://127.0.0.1:8000/test
&lt;span class="o"&gt;[&lt;/span&gt;2024-03-04T09:37:31+00:00] Counter: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, now the counter values for each response are the same as expected.&lt;/p&gt;

&lt;p&gt;And I worth to mention that &lt;a href="https://github.com/denzyldick/phanalist" rel="noopener noreferrer"&gt;phanalist&lt;/a&gt; is smart enough to not report controllers that implement &lt;code&gt;ResetInterface&lt;/code&gt; (configurable in &lt;code&gt;phanalist.yaml&lt;/code&gt;). So &lt;code&gt;./src/Controller/TestController.php&lt;/code&gt; is not included in its output anymore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% ~/phanalist &lt;span class="nt"&gt;-r&lt;/span&gt; E0012 &lt;span class="nt"&gt;-s&lt;/span&gt; ./src
Using configuration file ./phanalist.yaml

Scanning files &lt;span class="k"&gt;in&lt;/span&gt; ./src ...
██████████████████████████████████████████████████████████ 4/4
Analysed 2 files &lt;span class="k"&gt;in &lt;/span&gt;9.26ms, memory usage: 4.9 MiB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Shared Memory Model examples are reproducible only within the same worker, that's why all runtimes &lt;a href="https://github.com/SerheyDolgushev/php-shared-memory-model" rel="noopener noreferrer"&gt;php-shared-memory-model&lt;/a&gt; are forced to a single worker. Reproduce similar cases in a production environment there might be dozens for running workers might be very tricky.&lt;/p&gt;

&lt;p&gt;I hope this post introduced something new for you and provided you with a simple solution to a complex problem. Wish you to run your PHP apps faster and always get the expected results! &lt;/p&gt;

</description>
      <category>php</category>
      <category>symfony</category>
      <category>swoole</category>
      <category>frankenphp</category>
    </item>
  </channel>
</rss>
