<?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: Aleksei Gagarin</title>
    <description>The latest articles on DEV Community by Aleksei Gagarin (@roxblnfk).</description>
    <link>https://dev.to/roxblnfk</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%2F499527%2F77630837-10da-4bcb-8df2-e0d0ab2667c6.jpeg</url>
      <title>DEV Community: Aleksei Gagarin</title>
      <link>https://dev.to/roxblnfk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/roxblnfk"/>
    <language>en</language>
    <item>
      <title>To the Collider!</title>
      <dc:creator>Aleksei Gagarin</dc:creator>
      <pubDate>Tue, 17 Mar 2026 19:34:25 +0000</pubDate>
      <link>https://dev.to/roxblnfk/to-the-collider-179h</link>
      <guid>https://dev.to/roxblnfk/to-the-collider-179h</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;a href="https://php-testo.github.io/" rel="noopener noreferrer"&gt;Testo&lt;/a&gt; is a new PHP testing framework that lets you benchmark code with a single attribute — no extra tools, no boilerplate.&lt;/em&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;🤔 The Problem&lt;br&gt;
Write a function that calculates the sum of all numbers from &lt;code&gt;$a&lt;/code&gt; to &lt;code&gt;$b&lt;/code&gt;.&lt;br&gt;
For example, if &lt;code&gt;$a = 1&lt;/code&gt; and &lt;code&gt;$b = 5&lt;/code&gt;, the result is &lt;code&gt;1 + 2 + 3 + 4 + 5 = 15&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;The simplest solution that comes to mind:
iteratively add &lt;code&gt;$i&lt;/code&gt; to &lt;code&gt;$a&lt;/code&gt; in a &lt;code&gt;for&lt;/code&gt; loop until we reach &lt;code&gt;$b&lt;/code&gt;, but that's too obvious.&lt;/li&gt;
&lt;li&gt;Imagination takes over and you want to solve it with arrays:
fill an array with values from &lt;code&gt;$a&lt;/code&gt; to &lt;code&gt;$b&lt;/code&gt; and pass it to &lt;code&gt;sum()&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&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%2Fvntnu8oweuoblddjgow4.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%2Fvntnu8oweuoblddjgow4.png" alt="To the Collider!" width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing the Solutions
&lt;/h2&gt;

&lt;p&gt;PHP performs very well in synthetic benchmarks, outpacing Python and all that. With JIT enabled and a few tricks, it can even catch up to C++.&lt;/p&gt;

&lt;p&gt;We won't be comparing PHP with other languages right now — instead, let's just compare these two approaches against each other.&lt;/p&gt;

&lt;p&gt;Here's my reasoning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The array solution should be slower than the &lt;code&gt;for&lt;/code&gt; loop, since extra resources go into computing hashes for the hash table when creating the array, and more memory is needed for intermediate values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's verify this: we'll write the functions and add the &lt;code&gt;#[Bench]&lt;/code&gt; attribute to one of them.&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="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Bench&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;callables&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'in_array'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'sumInArray'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5_000&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;calls&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;iterations&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="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sumInCycle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$result&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="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sumInArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;\array_sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$b&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;With the &lt;code&gt;#[Bench]&lt;/code&gt; attribute, we're telling Testo that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we want to compare the performance of the current function (&lt;code&gt;sumInCycle&lt;/code&gt;) with another function (&lt;code&gt;sumInArray&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;both functions will receive the same arguments: &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;5_000&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;to measure execution time, each function will be called 100 times in a row (&lt;code&gt;calls: 100&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Place your bets and let's run it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Summary:
+---+-------------+-------+-------+--------+-------------------+
| # | Name        | Iters | Calls | Memory | Avg Time          |
+---+-------------+-------+-------+--------+-------------------+
| 2 | current     | 1     | 100   | 0      | 38.921ms          |
| 1 | sumInArray  | 1     | 100   | 0      | 21.472ms (-44.8%) |
+---+-------------+-------+-------+--------+-------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sumInArray&lt;/code&gt; takes first place, completing the task almost twice as fast as &lt;code&gt;sumInCycle&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Wait, what? The array-based function won by a wide margin?!&lt;/p&gt;
&lt;/blockquote&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%2F07f09h2mjby1uykvut8l.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%2F07f09h2mjby1uykvut8l.png" alt="Statistical Artifact" width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Statistical Artifact
&lt;/h2&gt;

&lt;p&gt;Indeed, this could just be a "statistical artifact."&lt;/p&gt;

&lt;p&gt;Each benchmark rerun produces different results, sometimes varying significantly from the previous ones.&lt;br&gt;
This can be caused by background tasks, user activity, or other phenomena that affect performance at the moment.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ We need guarantees that we're comparing genuinely stable results, not just random outliers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Statistics comes to the rescue with the &lt;a href="https://en.wikipedia.org/wiki/Coefficient_of_variation" rel="noopener noreferrer"&gt;coefficient of variation&lt;/a&gt;, which measures the relative variability of data.&lt;br&gt;
The smaller this coefficient, the more stable the results.&lt;/p&gt;

&lt;p&gt;All we need to do is collect more data spread over time — that is, rerun the benchmarks multiple times.&lt;br&gt;
The &lt;code&gt;#[Bench]&lt;/code&gt; attribute has an &lt;code&gt;iterations&lt;/code&gt; parameter responsible for the number of benchmark reruns.&lt;/p&gt;

&lt;p&gt;Let's set &lt;code&gt;iterations: 10&lt;/code&gt; and rerun:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Summary:
+---+-------------+-------+-------+--------+-------------------+---------+
| # | Name        | Iters | Calls | Memory | Avg Time          | RStDev  |
+---+-------------+-------+-------+--------+-------------------+---------+
| 2 | current     | 10    | 100   | 0      | 38.474ms          | ±2.86%  |
| 1 | sumInArray  | 10    | 100   | 0      | 12.501ms (-67.5%) | ±27.20% |
+---+-------------+-------+-------+--------+-------------------+---------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;sumInArray&lt;/code&gt; runs 3x faster, but the coefficient of variation (&lt;code&gt;RStDev&lt;/code&gt; column) is 27.2%, which is quite high.&lt;br&gt;
To claim stable results, you typically aim for RStDev &amp;lt; 2%.&lt;/p&gt;

&lt;p&gt;Let's think about how to reduce this variation. Our functions execute quite fast, and even small performance fluctuations can heavily impact the results, especially with a low number of runs.&lt;br&gt;
For fast code like ours, increasing the number of &lt;code&gt;calls&lt;/code&gt; per iteration can help. Let's bump it to 2000:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Summary:
+---+-------------+-------+-------+--------+-------------------+--------+
| # | Name        | Iters | Calls | Memory | Avg Time          | RStDev |
+---+-------------+-------+-------+--------+-------------------+--------+
| 2 | current     | 10    | 2000  | 0      | 37.888ms          | ±1.38% |
| 1 | sumInArray  | 10    | 2000  | 0      | 11.395ms (-69.9%) | ±1.72% |
+---+-------------+-------+-------+--------+-------------------+--------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, with a 3x performance difference, even ±27.2% variation wouldn't have saved the &lt;code&gt;for&lt;/code&gt; loop from defeat. But now we can confidently claim the results are stable (RStDev &amp;lt; 2%).&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%2Fqjbox48c7uexgbh8e2u1.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%2Fqjbox48c7uexgbh8e2u1.png" alt="Fine, arrays are faster" width="512" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By the way, did you notice that &lt;code&gt;memory=0&lt;/code&gt; in both cases? This means no additional memory was allocated for the arrays — what was already allocated at benchmark startup was enough.&lt;/p&gt;

&lt;p&gt;Of course, you could experiment with a larger range, enable JIT, and prove that in some cases the loop would be faster,&lt;br&gt;
but I want to draw your attention to how quick it is to benchmark something now!&lt;/p&gt;
&lt;h2&gt;
  
  
  #[Bench]
&lt;/h2&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%2Fv5zqgxr6to1vauoh4lnt.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%2Fv5zqgxr6to1vauoh4lnt.png" alt="Shock" width="684" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Benchmarking right in your code without extra boilerplate. Like &lt;a href="https://php-testo.github.io/docs/plugins/inline" rel="noopener noreferrer"&gt;inline tests&lt;/a&gt;, but for benchmarks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/TheDragonCode/benchmark" rel="noopener noreferrer"&gt;Dragon Code&lt;/a&gt; once showed that benchmarks can be simple and convenient: instead of tons of boilerplate, just call a single class and pass closures for comparison.&lt;br&gt;
Testo takes this to the next level: from intent to result in just one attribute.&lt;/p&gt;

&lt;p&gt;Run it with a single click in your IDE:&lt;br&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%2Fdlmqufdm4dd54p5566di.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%2Fdlmqufdm4dd54p5566di.png" alt="IDE" width="594" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But that's not all. Behind the simplicity on the surface lie serious algorithms backed by statistics.&lt;/p&gt;

&lt;p&gt;Testo automatically detects deviations in the data, discards outliers, and produces metrics that help you understand how stable the results are.&lt;br&gt;
For those who don't find raw numbers very telling, there's a summary with recommendations and alerts.&lt;/p&gt;

&lt;p&gt;Here's what it looks like right now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Results for calcFoo:
+----------------------------+-------------------------------------------------+------------------------------------+--------------------------------------------------------------+
| BENCHMARK SETUP            | TIME RESULTS                                    | FILTERED RESULTS                   | SUMMARY                                                      |
| Name       | Iters | Calls | Mean              | Median            | RStDev  | Rej. | Mean*             | RStDev* | Place | Warnings                                             |
+------------+-------+-------+-------------------+-------------------+---------+------+-------------------+---------+-------+------------------------------------------------------+
| current    | 10    | 20    | 44.03µs           | 43.68µs           |  ±2.35% | 1    | 43.69µs           |  ±0.42% | 3rd   |                                                      |
| calcBar    | 10    | 20    | 13.72µs (-68.8%)  | 13.26µs (-69.6%)  |  ±7.77% | 2    | 13.23µs (-69.7%)  |  ±0.52% | 2nd   |                                                      |
| calcBaz    | 10    | 20    | 110.50ns (-99.7%) | 105.00ns (-99.8%) | ±16.50% | 1    | 106.11ns (-99.8%) | ±12.52% | 1st   | High variance, low iter time. Insufficient iter time |
+------------+-------+-------+-------------------+-------------------+---------+------+-------------------+---------+-------+------------------------------------------------------+
Recommendations:
  ⚠ High variance, low iter time: Measurement overhead may dominate — increase calls per iteration.
  ⚠ Insufficient iter time: Timer jitter exceeds useful signal — increase calls per iteration.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I know, it looks overwhelming, but this isn't the release version yet. In the future I envision it being even simpler: an attribute with automatic settings, no need to dive into the details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back to the Collider
&lt;/h2&gt;

&lt;p&gt;Alright, you obviously know that the range sum problem can be solved in &lt;code&gt;O(1)&lt;/code&gt; using a simple mathematical formula.&lt;br&gt;
I'll deprive you of the pleasure of pointing this out in the comments.&lt;/p&gt;

&lt;p&gt;Here's the function and a benchmark against the previous solutions:&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sumLinearF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$a&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;$d&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="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$d&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$d&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Summary:
+---+-------------+-------+-------+-------------------+--------+
| # | Name        | Iters | Calls | Avg Time          | RStDev |
+---+-------------+-------+-------+-------------------+--------+
| 4 | current     | 10    | 2000  | 40.102ms          | ±1.09% |
| 2 | sumInArray  | 10    | 2000  | 12.232ms (-69.5%) | ±0.93% |
| 1 | sumLinear   | 10    | 2000  | 77.065µs (-99.8%) | ±3.05% |
+---+-------------+-------+-------+-------------------+--------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Microseconds instead of milliseconds. Pretty cool, right?&lt;/p&gt;

&lt;p&gt;And even here there's room for optimization. You've probably heard that division isn't always the fastest operation.&lt;br&gt;
Dividing by 2 can be replaced with multiplying by 0.5.&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%2Frinre2y41dnoq8lsouvh.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%2Frinre2y41dnoq8lsouvh.png" alt=" " width="800" height="250"&gt;&lt;/a&gt;&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$a&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;$d&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="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$d&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$d&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+---+---------+-------+---------+--------+------------------+--------+
| # | Name    | Iters | Calls   | Memory | Avg Time         | RStDev |
+---+---------+-------+---------+--------+------------------+--------+
| 1 | current | 10    | 2000000 | 0      | 75.890µs         | ±0.79% |
| 2 | multi   | 10    | 2000000 | 0      | 78.821µs (+3.9%) | ±0.47% |
+---+---------+-------+---------+--------+------------------+--------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Division is faster than multiplication (╯°□°）╯︵ ┻━━┻&lt;/p&gt;

&lt;p&gt;Expectations don't always match reality, and optimizations don't always work the way we think.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also, remembering that we're working with positive integers in binary, we can replace division with a bit shift, which in theory should be even faster.&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%2F4t5j5j9kha9n9r7258bn.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%2F4t5j5j9kha9n9r7258bn.png" alt="WTF" width="513" height="327"&gt;&lt;/a&gt;&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$a&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="nv"&gt;$d&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="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$d&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+---+---------+-------+---------+--------+------------------+--------+
| # | Name    | Iters | Calls   | Memory | Avg Time         | RStDev |
+---+---------+-------+---------+--------+------------------+--------+
| 2 | current | 10    | 2000000 | 0      | 75.890µs         | ±0.79% |
| 1 | shift   | 10    | 2000000 | 0      | 70.559µs (-7.0%) | ±0.70% |
+---+---------+-------+---------+--------+------------------+--------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At least the bit shift didn't let us down.&lt;/p&gt;

&lt;p&gt;Note that the 7% improvement doesn't mean bit shifting is exactly 7% faster than division.&lt;br&gt;
The function contains several other mathematical operations, and the function call itself takes some time.&lt;br&gt;
So 7% is the difference between two functions, not between two specific operations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 It's always important to understand what exactly is being compared, so you can correctly interpret the results.&lt;/p&gt;
&lt;/blockquote&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%2Fnhsmt7hqa2incfvn1ll7.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%2Fnhsmt7hqa2incfvn1ll7.png" alt="Benchmarks will tell" width="513" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use benchmarks, verify your assumptions, and find optimal solutions.&lt;/p&gt;

</description>
      <category>php</category>
      <category>benchmarks</category>
      <category>tooling</category>
      <category>performance</category>
    </item>
    <item>
      <title>PHP types</title>
      <dc:creator>Aleksei Gagarin</dc:creator>
      <pubDate>Sun, 07 May 2023 22:50:27 +0000</pubDate>
      <link>https://dev.to/roxblnfk/php-types-o8d</link>
      <guid>https://dev.to/roxblnfk/php-types-o8d</guid>
      <description>&lt;p&gt;It would be too trivial to say that following strict types and avoiding implicit conversions reduces code magic, which leads to stability and reliability.&lt;br&gt;
That's why in &lt;a href="https://github.com/spiral" rel="noopener noreferrer"&gt;Spiral&lt;/a&gt;, &lt;a href="https://github.com/yiisoft" rel="noopener noreferrer"&gt;Yii&lt;/a&gt;, &lt;a href="https://github.com/cycle" rel="noopener noreferrer"&gt;Cycle&lt;/a&gt; and other projects where I contribute, we use strict types whenever possible.&lt;br&gt;
It's kind of obvious, but... This is &lt;strong&gt;PHP&lt;/strong&gt;. And that means you can't do without nuances 💩&lt;/p&gt;
&lt;h2&gt;
  
  
  ⭕️ &lt;code&gt;declare(strict_types=1);&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Straight from the documentation: &lt;em&gt;by default, PHP will coerce values of the wrong type into the expected scalar type declaration if possible.&lt;/em&gt; ...&lt;br&gt;
&lt;em&gt;It is possible to enable strict mode on a per-file basis. In strict mode, only a value corresponding exactly to the type declaration will be accepted, otherwise a TypeError will be thrown. The only exception to this rule is that an int value will pass a float type declaration.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Warning&lt;/strong&gt; Function calls from within internal functions will not be affected by the &lt;code&gt;strict_types&lt;/code&gt; declaration.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Note the warning. Many core functions &lt;strong&gt;do not follow&lt;/strong&gt; type strictness.&lt;br&gt;
For example, &lt;code&gt;array_map()&lt;/code&gt; and &lt;code&gt;array_filter()&lt;/code&gt; will make an implicit type conversion.&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="nb"&gt;print_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;array_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'10'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'1e2'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// output:&lt;/span&gt;
&lt;span class="k"&gt;Array&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;103&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But &lt;code&gt;call_user_func()&lt;/code&gt; will complain about type mismatch.&lt;/p&gt;

&lt;p&gt;Reflection doesn't follow strict types too. So instead of calling &lt;code&gt;newInstanceArgs()&lt;/code&gt;/&lt;code&gt;newInstance()&lt;/code&gt; in the &lt;a href="https://github.com/spiral/core/blob/32a2d8694c81119bed633916b01b0f320442229d/src/Internal/Factory.php#L384" rel="noopener noreferrer"&gt;Container Factory&lt;/a&gt;, we have&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="nv"&gt;$instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nv"&gt;$class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It may be a little slower, but it's more reliable.&lt;/p&gt;

&lt;p&gt;Now let's go to hacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⭕️ Variable Typing
&lt;/h2&gt;

&lt;p&gt;With a simple hack you can bind a type to a variable.&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="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;makeInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nv"&gt;$list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$int&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="nf"&gt;makeInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 42&lt;/span&gt;
&lt;span class="nv"&gt;$int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Fatal error: Uncaught TypeError: Cannot assign string...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Don't use it because it leaks.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ⭕️ PHP 8.2
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt; and &lt;code&gt;true&lt;/code&gt; types can now be used stand-alone.&lt;br&gt;
What is this for? To provide covariance. For example, when extending a method, the return value with &lt;code&gt;bool&lt;/code&gt; can be narrowed down to &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;, and nullable (&lt;code&gt;?Foo&lt;/code&gt;) can be narrowed to less specific &lt;code&gt;null&lt;/code&gt;. There are a lot of such cases in libraries.&lt;/p&gt;

&lt;p&gt;The DNF (Disjunctive Normal Form) has arrived.&lt;br&gt;
Now you may meet such monster in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(Countable&amp;amp;Traversable)|array
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;p&gt;ℹ️ Curious but nullable-sugar (&lt;code&gt;?Foo&lt;/code&gt;) was added in PHP 7.1, before Union Types.&lt;br&gt;
ℹ️ Always explicitly specify the type of nullable parameters (&lt;code&gt;?Foo $foo = null&lt;/code&gt;) rather than relying only on the default null value (&lt;code&gt;Foo $foo = null&lt;/code&gt;).&lt;br&gt;
ℹ️ The &lt;code&gt;never&lt;/code&gt; type was added in PHP 8.1. But you don't need it if you use RoadRunner.&lt;br&gt;
ℹ️ The &lt;code&gt;callable&lt;/code&gt; type exists only in function and method signatures. It can't be used in properties, so you can't put it into Promoted properties either. That's because in different contexts callable can be different.&lt;br&gt;
So how can we get a &lt;code&gt;callable&lt;/code&gt; and write it to a property? For example like this:&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="c1"&gt;// A class declaration&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;\Closure&lt;/span&gt; &lt;span class="nv"&gt;$callback&lt;/span&gt;&lt;span class="p"&gt;;&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;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;callable&lt;/span&gt; &lt;span class="nv"&gt;$callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&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;callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&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;



</description>
      <category>php</category>
      <category>yii</category>
      <category>spiral</category>
      <category>cycle</category>
    </item>
    <item>
      <title>RoadRunner video tutorials</title>
      <dc:creator>Aleksei Gagarin</dc:creator>
      <pubDate>Fri, 01 Jul 2022 18:15:59 +0000</pubDate>
      <link>https://dev.to/roxblnfk/roadrunner-video-tutorials-nim</link>
      <guid>https://dev.to/roxblnfk/roadrunner-video-tutorials-nim</guid>
      <description>&lt;p&gt;First fifteen videos about RoadRunner &lt;a href="https://www.youtube.com/playlist?list=PLL6_RArGSORJ2OU4qn8rJmIwSGBIc8C_X" rel="noopener noreferrer"&gt;have been committed&lt;/a&gt;.&lt;br&gt;
Videos about Spiral Framework in progress.&lt;/p&gt;

&lt;p&gt;Do you use the RoadRunner with your PHP Application?&lt;/p&gt;

</description>
      <category>roadrunner</category>
      <category>php</category>
      <category>spiral</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
