<?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>Jit on Guillaume Delré</title><link>https://guillaumedelre.github.io/fr/tags/jit/</link><description>Recent content in Jit on Guillaume Delré</description><generator>Hugo</generator><language>fr-FR</language><lastBuildDate>Sun, 10 Jan 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://guillaumedelre.github.io/fr/tags/jit/index.xml" rel="self" type="application/rss+xml"/><item><title>PHP 8.0 : match, arguments nommés, attributs et JIT</title><link>https://guillaumedelre.github.io/fr/2021/01/10/php-8.0-match-arguments-nomm%C3%A9s-attributs-et-jit/</link><pubDate>Sun, 10 Jan 2021 00:00:00 +0000</pubDate><guid>https://guillaumedelre.github.io/fr/2021/01/10/php-8.0-match-arguments-nomm%C3%A9s-attributs-et-jit/</guid><description>Part 6 of 11 in &amp;quot;Sorties PHP&amp;quot;: PHP 8.0 remodèle le langage : compilateur JIT, arguments nommés, expressions match, types union et opérateur nullsafe.</description><category>php-releases</category><content:encoded><![CDATA[<p>PHP 8.0 est sorti le 26 novembre. Je le fais tourner depuis six semaines sur un projet perso et un nouveau service au boulot. C&rsquo;est la version PHP la plus significative depuis 7.0, et à certains égards plus impactante, parce que les changements se renforcent mutuellement de façon utile.</p>
<h2 id="jit">JIT</h2>
<p>Le compilateur Just-In-Time était l&rsquo;annonce principale. La réalité en production est plus nuancée : pour les applications web typiques (requêtes en base, appels HTTP, rendu de templates) les gains sont modestes, parce que ces workloads sont limités par les I/O, pas par le calcul. Là où le JIT brille vraiment, c&rsquo;est le code intensif en CPU : manipulation d&rsquo;images, transformation de données, calcul mathématique.</p>
<p>Pour la plupart des applications web, l&rsquo;amélioration de performance vient du travail sur le moteur en général dans 8.0, pas du JIT spécifiquement. Vaut quand même la peine de l&rsquo;activer : ça ne coûte rien sur les workloads I/O-bound.</p>
<h2 id="les-expressions-match">Les expressions match</h2>
<p><code>switch</code> a trois problèmes : il utilise la comparaison souple, il tombe en cascade par défaut, et il ne peut pas être utilisé comme expression. <code>match</code> règle les trois :</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>$result <span style="color:#f92672">=</span> <span style="color:#a6e22e">match</span>($status) {
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;active&#39;</span>, <span style="color:#e6db74">&#39;pending&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;processing&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;done&#39;</span>             <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;finished&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">default</span>            <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\UnexpectedValueException</span>($status),
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>Comparaison stricte. Pas de cascade. Expression qui retourne une valeur. Un match non exhaustif lève une exception. Après une semaine avec <code>match</code>, j&rsquo;ai arrêté d&rsquo;écrire des <code>switch</code>.</p>
<h2 id="les-arguments-nommés">Les arguments nommés</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><span style="color:#a6e22e">array_slice</span>(<span style="color:#66d9ef">array</span><span style="color:#f92672">:</span> $users, <span style="color:#a6e22e">offset</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">0</span>, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">10</span>, <span style="color:#a6e22e">preserve_keys</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>);
</span></span></code></pre></div><p>Les arguments nommés permettent de passer les arguments dans n&rsquo;importe quel ordre et d&rsquo;en sauter des optionnels. Le gain évident : la lisibilité sur les fonctions avec plusieurs flags booléens. Le gain moins évident : les arguments nommés survivent aux mises à jour de PHP même quand l&rsquo;ordre des paramètres change, parce qu&rsquo;on nomme ce qu&rsquo;on veut dire.</p>
<h2 id="les-attributs">Les attributs</h2>
<p>Place aux docblock annotations (le style <code>@Route</code>, <code>@ORM\Column</code> sur lequel les frameworks se sont appuyés pendant des années), bienvenue à la syntaxe PHP de première classe :</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">#[Route(&#39;/users&#39;, methods: [&#39;GET&#39;])]
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#[IsGranted(&#39;ROLE_ADMIN&#39;)]
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">list</span>()<span style="color:#f92672">:</span> <span style="color:#a6e22e">Response</span> { <span style="color:#f92672">...</span> }
</span></span></code></pre></div><p>Les attributs sont validés par le moteur, pas parsés depuis des strings. Le support IDE fonctionne directement, sans magie de plugin. Pour les utilisateurs de Symfony et Doctrine, c&rsquo;est le vrai gain quotidien de PHP 8.0.</p>
<h2 id="la-promotion-de-constructeur">La promotion de constructeur</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><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">string</span> $name,
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#f92672">?</span><span style="color:#a6e22e">string</span> $email <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span>,
</span></span><span style="display:flex;"><span>    ) {}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Propriétés déclarées et assignées en une ligne dans la signature du constructeur. Le gain de refactoring le plus immédiat dans 8.0 : chaque classe de données que j&rsquo;ai touchée depuis la mise à jour fait moitié moins de lignes qu&rsquo;avant.</p>
<h2 id="lopérateur-nullsafe">L&rsquo;opérateur nullsafe</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>$city <span style="color:#f92672">=</span> $user<span style="color:#f92672">?-&gt;</span><span style="color:#a6e22e">getAddress</span>()<span style="color:#f92672">?-&gt;</span><span style="color:#a6e22e">getCity</span>()<span style="color:#f92672">?-&gt;</span><span style="color:#a6e22e">getName</span>();
</span></span></code></pre></div><p><code>null</code> à n&rsquo;importe quel point de la chaîne court-circuite le reste et retourne <code>null</code>. L&rsquo;alternative était des null checks imbriqués ou une chaîne de retours anticipés. Ça se compose naturellement.</p>
<h2 id="les-types-union">Les types union</h2>
<p>Les arguments nommés rendent les signatures de fonctions plus explicites au site d&rsquo;appel. Les types union les rendent plus honnêtes au site de déclaration :</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">processInput</span>(<span style="color:#a6e22e">int</span><span style="color:#f92672">|</span><span style="color:#a6e22e">float</span><span style="color:#f92672">|</span><span style="color:#a6e22e">string</span> $value)<span style="color:#f92672">:</span> <span style="color:#a6e22e">string</span><span style="color:#f92672">|</span><span style="color:#a6e22e">int</span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">is_string</span>($value)) {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">strlen</span>($value);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> (<span style="color:#a6e22e">int</span>) <span style="color:#a6e22e">round</span>($value);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>L&rsquo;union <code>int|float|string</code> est un OU littéral. Le moteur l&rsquo;impose à l&rsquo;entrée et à la sortie. Avant 8.0, &ldquo;ce paramètre accepte int ou float&rdquo; vivait dans un docblock que rien n&rsquo;imposait. Il y a aussi <code>null</code> comme composant de type : <code>?string</code> est juste du sucre syntaxique pour <code>string|null</code>, les deux sont valides.</p>
<p>Un cas spécial : <code>false</code>. PHP a un tas de fonctions natives qui retournent une valeur typée en cas de succès et <code>false</code> en cas d&rsquo;échec. Le système de types de 8.0 accommode ça : <code>array|false</code>, <code>string|false</code>. C&rsquo;est une reconnaissance honnête que la codebase ne peut pas être réécrite du jour au lendemain.</p>
<h2 id="le-type-de-retour-static">Le type de retour static</h2>
<p><code>static</code> comme type de retour était possible de manière informelle via les docblocks, mais 8.0 le rend officiel. La distinction entre <code>self</code> et <code>static</code> compte dans l&rsquo;héritage :</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">Builder</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">protected</span> <span style="color:#66d9ef">array</span> $config <span style="color:#f92672">=</span> [];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">set</span>(<span style="color:#a6e22e">string</span> $key, <span style="color:#a6e22e">mixed</span> $value)<span style="color:#f92672">:</span> <span style="color:#66d9ef">static</span> {
</span></span><span style="display:flex;"><span>        $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">config</span>[$key] <span style="color:#f92672">=</span> $value;
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> $this;
</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">class</span> <span style="color:#a6e22e">SpecialBuilder</span> <span style="color:#66d9ef">extends</span> <span style="color:#a6e22e">Builder</span> {}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$result <span style="color:#f92672">=</span> (<span style="color:#66d9ef">new</span> <span style="color:#a6e22e">SpecialBuilder</span>())<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">set</span>(<span style="color:#e6db74">&#39;foo&#39;</span>, <span style="color:#e6db74">&#39;bar&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#75715e">// $result est SpecialBuilder, pas Builder
</span></span></span></code></pre></div><p>Avec <code>self</code> comme type de retour, cette chaîne retournerait <code>Builder</code>, cassant les interfaces fluides dans les sous-classes. <code>static</code> fait fonctionner correctement les APIs fluides à travers les hiérarchies d&rsquo;héritage sans surcharges manuelles.</p>
<h2 id="le-type-mixed">Le type mixed</h2>
<p><code>mixed</code> était une convention de docblock pendant des années. 8.0 en fait un vrai type qui apparaît dans les signatures :</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">debug</span>(<span style="color:#a6e22e">mixed</span> $value)<span style="color:#f92672">:</span> <span style="color:#a6e22e">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">var_dump</span>($value);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Il accepte tout : <code>null</code>, objets, ressources, scalaires, tableaux. Sémantiquement c&rsquo;est la même chose que n&rsquo;avoir aucune déclaration de type, mais c&rsquo;est explicite plutôt qu&rsquo;absent. La différence entre &ldquo;ce paramètre est non typé&rdquo; et &ldquo;ce paramètre accepte intentionnellement n&rsquo;importe quoi.&rdquo; Vaut la peine de l&rsquo;utiliser quand on écrit un utilitaire généraliste qui serait malhonnête avec un type plus étroit.</p>
<h2 id="throw-comme-expression">throw comme expression</h2>
<p>Avant 8.0, <code>throw</code> était une instruction. Ça semble une distinction pédante jusqu&rsquo;à ce qu&rsquo;on tombe sur les endroits où on veut vraiment une expression :</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">// Dans un ternaire :
</span></span></span><span style="display:flex;"><span>$value <span style="color:#f92672">=</span> $input <span style="color:#f92672">??</span> <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\InvalidArgumentException</span>(<span style="color:#e6db74">&#39;input required&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Dans une arrow function :
</span></span></span><span style="display:flex;"><span>$getId <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>(<span style="color:#a6e22e">User</span> $u) <span style="color:#f92672">=&gt;</span> $u<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">id</span> <span style="color:#f92672">??</span> <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\RuntimeException</span>(<span style="color:#e6db74">&#39;no id&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Dans un bras match (qui est déjà une expression) :
</span></span></span><span style="display:flex;"><span>$status <span style="color:#f92672">=</span> <span style="color:#a6e22e">match</span>($code) {
</span></span><span style="display:flex;"><span>    <span style="color:#ae81ff">200</span>     <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;ok&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ae81ff">404</span>     <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;not found&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\UnexpectedValueException</span>(<span style="color:#e6db74">&#34;unknown code: </span><span style="color:#e6db74">$code</span><span style="color:#e6db74">&#34;</span>),
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>Le dernier est particulièrement utile : un match sans default lancera <code>UnhandledMatchError</code> automatiquement, mais parfois on veut contrôler le type d&rsquo;exception et le message.</p>
<h2 id="catch-sans-variable">catch sans variable</h2>
<p>Petite amélioration de qualité de vie. Quand on attrape une exception mais qu&rsquo;on n&rsquo;utilise pas réellement l&rsquo;objet, 8.0 permet d&rsquo;omettre la variable :</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">try</span> {
</span></span><span style="display:flex;"><span>    $result <span style="color:#f92672">=</span> $cache<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">get</span>($key);
</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">catch</span> (<span style="color:#a6e22e">CacheMissException</span>) {
</span></span><span style="display:flex;"><span>    $result <span style="color:#f92672">=</span> $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">compute</span>($key);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Avant 8.0, il fallait écrire <code>catch (CacheMissException $e)</code> et ensuite soit utiliser <code>$e</code> soit vivre avec l&rsquo;avertissement IDE sur la variable inutilisée. Aucune des deux options n&rsquo;était satisfaisante.</p>
<h2 id="les-fonctions-string-qui-auraient-dû-exister-depuis-des-années">Les fonctions string qui auraient dû exister depuis des années</h2>
<p>Trois fonctions que chaque développeur PHP a écrites manuellement au moins une fois :</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">&#39;hello world&#39;</span>, <span style="color:#e6db74">&#39;world&#39;</span>);  <span style="color:#75715e">// true
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">str_starts_with</span>(<span style="color:#e6db74">&#39;hello world&#39;</span>, <span style="color:#e6db74">&#39;hell&#39;</span>); <span style="color:#75715e">// true
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">str_ends_with</span>(<span style="color:#e6db74">&#39;hello world&#39;</span>, <span style="color:#e6db74">&#39;world&#39;</span>); <span style="color:#75715e">// true
</span></span></span></code></pre></div><p>Avant 8.0, les approches habituelles étaient <code>strpos() !== false</code>, <code>strncmp()</code>, ou <code>substr() ===</code>, qui nécessitent toutes de s&rsquo;arrêter pour se souvenir de la sémantique. Ces nouvelles fonctions sont juste directes et lisibles. Pas de regex, pas d&rsquo;arithmétique d&rsquo;offset.</p>
<h2 id="un-tri-stable">Un tri stable</h2>
<p>Les fonctions de tri de PHP n&rsquo;étaient pas stables avant 8.0. &ldquo;Pas stable&rdquo; signifie que les éléments qui se comparent comme égaux pouvaient se retrouver dans n&rsquo;importe quel ordre les uns par rapport aux autres. En pratique, ça causait des bugs subtils dans le code UI qui avait besoin d&rsquo;un ordre cohérent, une pagination qui changeait entre les chargements, et des tests qui ne passaient que par chance.</p>
<p>8.0 garantit la stabilité à travers toutes les fonctions de tri : <code>sort()</code>, <code>usort()</code>, <code>array_multisort()</code>, et le reste. Les éléments égaux conservent leur position relative originale. C&rsquo;est le comportement que la plupart des gens supposaient déjà être là.</p>
<h2 id="weakmap">WeakMap</h2>
<p>7.4 apportait <code>WeakReference</code> pour les objets simples. 8.0 apporte <code>WeakMap</code> : une map où les clés (des objets) et leurs données associées peuvent être ramassées par le GC quand aucune autre référence à l&rsquo;objet-clé n&rsquo;existe :</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">RequestCache</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">WeakMap</span> $cache;
</span></span><span style="display:flex;"><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>        $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">cache</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">WeakMap</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">public</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">get</span>(<span style="color:#a6e22e">Request</span> $request)<span style="color:#f92672">:</span> <span style="color:#a6e22e">Response</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">cache</span>[$request] <span style="color:#f92672">??=</span> $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">compute</span>($request);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Dès que <code>$request</code> n&rsquo;est plus référencé ailleurs, l&rsquo;entrée disparaît de la map. Pas de nettoyage manuel nécessaire. C&rsquo;est le bon pattern pour la mémoïsation et les caches de propriétés calculées où on ne veut pas être la seule raison qu&rsquo;un objet reste vivant.</p>
<h2 id="les-nouveaux-types-dexception">Les nouveaux types d&rsquo;exception</h2>
<p><code>ValueError</code> est levée quand une fonction reçoit le bon type mais une valeur invalide, par opposition à <code>TypeError</code> qui se déclenche sur les mauvais types :</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">array_chunk</span>([], <span style="color:#f92672">-</span><span style="color:#ae81ff">5</span>); <span style="color:#75715e">// ValueError: array_chunk(): Argument #2 ($length) must be greater than 0
</span></span></span></code></pre></div><p>Avant 8.0, beaucoup de ces cas étaient des warnings qui retournaient <code>false</code> ou <code>null</code>. Maintenant ils lèvent des exceptions. Le moteur est plus strict, ce qui signifie qu&rsquo;on attrape les problèmes plus tôt plutôt que d&rsquo;obtenir des résultats bizarres quelque part en aval.</p>
<h2 id="get_debug_type-et-fdiv">get_debug_type() et fdiv()</h2>
<p>Deux fonctions utilitaires à connaître.</p>
<p><code>get_debug_type()</code> retourne une représentation string normalisée de n&rsquo;importe quelle valeur, pratique pour les messages d&rsquo;erreur :</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">get_debug_type</span>(<span style="color:#ae81ff">1</span>);          <span style="color:#75715e">// &#34;int&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">get_debug_type</span>(<span style="color:#ae81ff">1.0</span>);        <span style="color:#75715e">// &#34;float&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">get_debug_type</span>(<span style="color:#66d9ef">null</span>);       <span style="color:#75715e">// &#34;null&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">get_debug_type</span>(<span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Foo</span>());  <span style="color:#75715e">// &#34;Foo&#34; (pas &#34;object&#34;)
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">get_debug_type</span>([]);         <span style="color:#75715e">// &#34;array&#34;
</span></span></span></code></pre></div><p>La différence avec <code>gettype()</code> : elle retourne les noms de classes pour les objets et utilise des noms normalisés (<code>&quot;int&quot;</code> pas <code>&quot;integer&quot;</code>). Exactement ce qu&rsquo;on veut pour construire un message d&rsquo;exception qui dit ce qu&rsquo;on a reçu versus ce qu&rsquo;on attendait.</p>
<p><code>fdiv()</code> effectue une division en virgule flottante suivant IEEE 754, ce qui signifie que la division par zéro retourne <code>INF</code>, <code>-INF</code>, ou <code>NAN</code> au lieu d&rsquo;un warning :</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">fdiv</span>(<span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">0</span>);   <span style="color:#75715e">// INF
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">fdiv</span>(<span style="color:#f92672">-</span><span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">0</span>);  <span style="color:#75715e">// -INF
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">fdiv</span>(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>);    <span style="color:#75715e">// NAN
</span></span></span></code></pre></div><h2 id="les-changements-qui-cassent-des-choses">Les changements qui cassent des choses</h2>
<p>8.0 inclut aussi quelques changements qui ne sont pas des fonctionnalités, ce sont des corrections.</p>
<p>Le plus important : <code>0 == &quot;foo&quot;</code> est maintenant <code>false</code>. En PHP 7, comparer un entier à une string non numérique castait la string en 0, donc <code>0 == &quot;n'importe-quoi-non-numérique&quot;</code> s&rsquo;évaluait à <code>true</code>. C&rsquo;était une source persistante de bugs et de maux de tête de sécurité. PHP 8 l&rsquo;inverse : l&rsquo;entier est casté en string à la place :</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">var_dump</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;foo&#34;</span>);  <span style="color:#75715e">// bool(false) en 8.0, bool(true) en 7.x
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">var_dump</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;&#34;</span>);     <span style="color:#75715e">// bool(false) en 8.0, bool(true) en 7.x
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">var_dump</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;0&#34;</span>);    <span style="color:#75715e">// bool(true) dans les deux (&#34;0&#34; est numérique)
</span></span></span></code></pre></div><p>Si on s&rsquo;appuyait sur ça intentionnellement, on savait déjà que c&rsquo;était douteux. Si on ne savait pas qu&rsquo;on s&rsquo;en appuyait, 8.0 va trouver ces chemins de code.</p>
<p>Plusieurs fonctions qui retournaient des ressources retournent maintenant des objets propres : <code>curl_init()</code> retourne un <code>CurlHandle</code>, <code>imagecreate()</code> retourne un <code>GdImage</code>, <code>xml_parser_create()</code> retourne un <code>XMLParser</code>. Le code qui vérifie <code>is_resource($curl)</code> va casser, parce que <code>is_resource()</code> retourne <code>false</code> pour ces objets. La correction consiste à vérifier contre <code>false</code> (la valeur de retour en cas d&rsquo;échec) plutôt que de vérifier le type du cas de succès.</p>
<p>PHP 8.0 est le genre de version où les fonctionnalités se renforcent mutuellement. Les attributs se marient bien avec la promotion de constructeur. Match s&rsquo;associe naturellement avec les types union. Les fonctions string réduisent le bruit qui cachait l&rsquo;intention. Les corrections sont parfois cassantes, mais elles poussent le langage vers une cohérence qu&rsquo;il aurait dû avoir depuis des années.</p>
]]></content:encoded></item></channel></rss>