<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Fibers on Guillaume Delré</title><link>https://guillaumedelre.github.io/tags/fibers/</link><description>Recent content in Fibers on Guillaume Delré</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 09 Jan 2022 00:00:00 +0000</lastBuildDate><atom:link href="https://guillaumedelre.github.io/tags/fibers/index.xml" rel="self" type="application/rss+xml"/><item><title>PHP 8.1: enums, fibers, and the type system growing up</title><link>https://guillaumedelre.github.io/2022/01/09/php-8.1-enums-fibers-and-the-type-system-growing-up/</link><pubDate>Sun, 09 Jan 2022 00:00:00 +0000</pubDate><guid>https://guillaumedelre.github.io/2022/01/09/php-8.1-enums-fibers-and-the-type-system-growing-up/</guid><description>Part 7 of 11 in &amp;quot;PHP Releases&amp;quot;: PHP 8.1 adds native enums, fibers for cooperative multitasking, readonly properties, and intersection types.</description><category>php-releases</category><content:encoded><![CDATA[<p>PHP 8.1 released November 25th. It follows 8.0&rsquo;s sweeping overhaul with something different: fewer features, but each one thought through rather than bolted on.</p>
<h2 id="enums">Enums</h2>
<p>This is the one that changes codebases the moment you upgrade. Before 8.1, PHP enumerations were either class constants, strings, or integers with nothing enforcing them:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#75715e">// before: nothing stops Status::INVALID from being passed
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">ACTIVE</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;active&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">INACTIVE</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;inactive&#39;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// after
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">enum</span> <span style="color:#a6e22e">Status</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">string</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">case</span> <span style="color:#a6e22e">Active</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;active&#39;</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">case</span> <span style="color:#a6e22e">Inactive</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;inactive&#39;</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">activate</span>(<span style="color:#a6e22e">Status</span> $status)<span style="color:#f92672">:</span> <span style="color:#a6e22e">void</span> { <span style="color:#f92672">...</span> }
</span></span></code></pre></div><p>PHP enums are objects, not scalars. They support methods, interfaces, and constants. Backed enums (with a string or int value) serialize cleanly and map to database columns naturally. Pure enums (no backing type) enforce domain concepts without worrying about serialization.</p>
<p>The immediate effect: every status field, every finite set of states in every codebase I maintain became an enum candidate. The type system finally has a native way to express the thing every PHP project has been faking for years.</p>
<h2 id="fibers">Fibers</h2>
<p>Fibers are a cooperative concurrency primitive: you can pause and resume execution of a function, yielding control without threads.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$fiber <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Fiber</span>(<span style="color:#66d9ef">function</span>()<span style="color:#f92672">:</span> <span style="color:#a6e22e">void</span> {
</span></span><span style="display:flex;"><span>    $value <span style="color:#f92672">=</span> <span style="color:#a6e22e">Fiber</span><span style="color:#f92672">::</span><span style="color:#a6e22e">suspend</span>(<span style="color:#e6db74">&#39;first&#39;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Resumed with: </span><span style="color:#e6db74">{</span>$value<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$result <span style="color:#f92672">=</span> $fiber<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">start</span>();    <span style="color:#75715e">// &#39;first&#39;
</span></span></span><span style="display:flex;"><span>$fiber<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">resume</span>(<span style="color:#e6db74">&#39;hello&#39;</span>);      <span style="color:#75715e">// &#34;Resumed with: hello&#34;
</span></span></span></code></pre></div><p>Fibers are the foundation async libraries like ReactPHP and Amp have needed from the runtime for a while. For most application developers the direct API matters less than the libraries built on top of it, but understanding fibers explains what those libraries are doing underneath.</p>
<h2 id="pencil2-readonly-properties">:pencil2: Readonly properties</h2>
<p>8.0 brought constructor promotion. 8.1 adds <code>readonly</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">User</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">__construct</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">readonly</span> <span style="color:#a6e22e">int</span> $id,
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">readonly</span> <span style="color:#a6e22e">string</span> $name,
</span></span><span style="display:flex;"><span>    ) {}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>A <code>readonly</code> property can be written exactly once, during initialization. After that, any write throws an <code>Error</code>. Combined with constructor promotion, value objects and DTOs become concise and actually mean what they say.</p>
<h2 id="first-class-callable-syntax">First-class callable syntax</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$fn <span style="color:#f92672">=</span> <span style="color:#a6e22e">strlen</span>(<span style="color:#f92672">...</span>);
</span></span><span style="display:flex;"><span>$fn <span style="color:#f92672">=</span> $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">process</span>(<span style="color:#f92672">...</span>);
</span></span><span style="display:flex;"><span>$fn <span style="color:#f92672">=</span> <span style="color:#a6e22e">MyClass</span><span style="color:#f92672">::</span><span style="color:#a6e22e">create</span>(<span style="color:#f92672">...</span>);
</span></span></code></pre></div><p><code>...</code> after a callable creates a <code>Closure</code> without <code>Closure::fromCallable()</code> boilerplate. Useful when passing methods as callbacks.</p>
<p>8.1 is precise. Enums alone justify the upgrade.</p>
<h2 id="intersection-types">Intersection types</h2>
<p>Union types landed in 8.0. Intersection types follow in 8.1. Where a union says &ldquo;one of these&rdquo;, an intersection says &ldquo;all of these&rdquo;:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">process</span>(<span style="color:#a6e22e">Countable</span><span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Iterator</span> $collection)<span style="color:#f92672">:</span> <span style="color:#a6e22e">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">foreach</span> ($collection <span style="color:#66d9ef">as</span> $item) { <span style="color:#75715e">/* ... */</span> }
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">count</span>($collection);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>One constraint: intersection types can&rsquo;t be mixed with union types in the same declaration (that arrives in 8.2 as DNF types). But this already unlocks precise type-checking for objects that must satisfy multiple interfaces at once, a pattern frameworks use constantly that had to stay untyped until now.</p>
<h2 id="the-never-return-type">The <code>never</code> return type</h2>
<p>A function that never returns (it always throws or exits) now has a type to say so:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">redirect</span>(<span style="color:#a6e22e">string</span> $url)<span style="color:#f92672">:</span> <span style="color:#a6e22e">never</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">header</span>(<span style="color:#e6db74">&#34;Location: </span><span style="color:#e6db74">{</span>$url<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">exit</span>();
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">fail</span>(<span style="color:#a6e22e">string</span> $message)<span style="color:#f92672">:</span> <span style="color:#a6e22e">never</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\RuntimeException</span>($message);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The practical benefit: static analyzers can prove that code after a <code>never</code> function is unreachable, and callers know there&rsquo;s no return value to handle. Before this, it lived in docblocks with no enforcement.</p>
<h2 id="final-class-constants">Final class constants</h2>
<p>Before 8.1, any subclass could quietly override a parent&rsquo;s class constant. Now you can put a stop to that:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Base</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">const</span> <span style="color:#66d9ef">VERSION</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;1.0&#39;</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Child</span> <span style="color:#66d9ef">extends</span> <span style="color:#a6e22e">Base</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Fatal error: Cannot override final constant Base::VERSION
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">const</span> <span style="color:#66d9ef">VERSION</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;2.0&#39;</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Relatedly, interface constants are now overridable by implementing classes by default. A separate behavior fix that had been inconsistent since interfaces were introduced.</p>
<h2 id="new-in-initializers"><code>new</code> in initializers</h2>
<p>Default parameter values used to be restricted to scalars and arrays. 8.1 drops that restriction:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Logger</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">__construct</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Handler</span> $handler <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">NullHandler</span>(),
</span></span><span style="display:flex;"><span>    ) {}
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">createUser</span>(
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">Validator</span> $validator <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">DefaultValidator</span>(),
</span></span><span style="display:flex;"><span>)<span style="color:#f92672">:</span> <span style="color:#a6e22e">User</span> { <span style="color:#75715e">/* ... */</span> }
</span></span></code></pre></div><p>Same goes for attribute arguments and static variable initializers. Which means dependency injection with sensible defaults no longer needs a null check and lazy instantiation inside the method body.</p>
<h2 id="array-unpacking-with-string-keys">Array unpacking with string keys</h2>
<p>Array unpacking via the spread operator only worked with integer-keyed arrays before 8.1. String keys work now too:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$defaults <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#39;color&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;red&#39;</span>, <span style="color:#e6db74">&#39;size&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;M&#39;</span>];
</span></span><span style="display:flex;"><span>$custom <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#39;size&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;L&#39;</span>, <span style="color:#e6db74">&#39;weight&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;200g&#39;</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$merged <span style="color:#f92672">=</span> [<span style="color:#f92672">...</span>$defaults, <span style="color:#f92672">...</span>$custom];
</span></span><span style="display:flex;"><span><span style="color:#75715e">// [&#39;color&#39; =&gt; &#39;red&#39;, &#39;size&#39; =&gt; &#39;L&#39;, &#39;weight&#39; =&gt; &#39;200g&#39;]
</span></span></span></code></pre></div><p>Later keys override earlier ones. Same behavior as <code>array_merge()</code>, but expressed inline. Performance difference is marginal; readability difference is not.</p>
<h2 id="fsync-and-fdatasync"><code>fsync</code> and <code>fdatasync</code></h2>
<p>Two functions that had no good reason to be missing from a filesystem-oriented language:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$fp <span style="color:#f92672">=</span> <span style="color:#a6e22e">fopen</span>(<span style="color:#e6db74">&#39;/tmp/important.dat&#39;</span>, <span style="color:#e6db74">&#39;w&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">fwrite</span>($fp, $data);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">fsync</span>($fp);   <span style="color:#75715e">// flush OS buffers to physical storage
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">fclose</span>($fp);
</span></span></code></pre></div><p><code>fdatasync()</code> does the same but skips metadata sync when you only care about the data being durable. Both return <code>false</code> on failure. If you&rsquo;re writing anything that needs crash safety, you needed these.</p>
<h2 id="passing-null-to-non-nullable-built-in-parameters">Passing <code>null</code> to non-nullable built-in parameters</h2>
<p>A quieter but consequential change: built-in functions that accept strings, integers, etc. have always silently swallowed <code>null</code> and coerced it. In 8.1, that starts emitting a deprecation notice.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">str_contains</span>(<span style="color:#e6db74">&#34;foobar&#34;</span>, <span style="color:#66d9ef">null</span>);
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Deprecated: Passing null to parameter #2 ($needle) of type string is deprecated
</span></span></span></code></pre></div><p>This aligns built-in functions with user-defined functions, which already refused nullable arguments for non-nullable parameters. PHP 9.0 turns this into a hard error. If you&rsquo;re passing <code>null</code> into string functions, now is a better time to fix it than during a production incident.</p>
<h2 id="mysqli-exceptions-by-default">MySQLi exceptions by default</h2>
<p>Before 8.1, MySQLi failed silently unless you explicitly called <code>mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT)</code>. That&rsquo;s now the default:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#75715e">// This throws \mysqli_sql_exception on connection failure in 8.1
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Previously returned false and set an error you had to check manually
</span></span></span><span style="display:flex;"><span>$connection <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">mysqli</span>(<span style="color:#e6db74">&#39;localhost&#39;</span>, <span style="color:#e6db74">&#39;user&#39;</span>, <span style="color:#e6db74">&#39;wrong_password&#39;</span>, <span style="color:#e6db74">&#39;db&#39;</span>);
</span></span></code></pre></div><p>Every codebase that catches MySQLi errors by checking return values needs to be reviewed. The silent failures that caused hard-to-diagnose bugs now throw exceptions, which is the right behavior, just potentially surprising if you hit it mid-upgrade.</p>
]]></content:encoded></item></channel></rss>