<?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>Performance on Guillaume Delré</title><link>https://guillaumedelre.github.io/fr/tags/performance/</link><description>Recent content in Performance on Guillaume Delré</description><generator>Hugo</generator><language>fr-FR</language><lastBuildDate>Sun, 12 Jan 2020 00:00:00 +0000</lastBuildDate><atom:link href="https://guillaumedelre.github.io/fr/tags/performance/index.xml" rel="self" type="application/rss+xml"/><item><title>PHP 7.4 : les propriétés typées et les arrow functions qu'on attendait</title><link>https://guillaumedelre.github.io/fr/2020/01/12/php-7.4-les-propri%C3%A9t%C3%A9s-typ%C3%A9es-et-les-arrow-functions-quon-attendait/</link><pubDate>Sun, 12 Jan 2020 00:00:00 +0000</pubDate><guid>https://guillaumedelre.github.io/fr/2020/01/12/php-7.4-les-propri%C3%A9t%C3%A9s-typ%C3%A9es-et-les-arrow-functions-quon-attendait/</guid><description>Part 5 of 11 in &amp;quot;Sorties PHP&amp;quot;: PHP 7.4 apporte les propriétés typées et les arrow functions concises — dernière version 7.x et prévisualisation la plus claire de PHP 8.</description><category>php-releases</category><content:encoded><![CDATA[<p>PHP 7.4 est sorti le 28 novembre. C&rsquo;est la dernière version 7.x avant PHP 8.0, et ça se sent. Les fonctionnalités sont suffisamment substantielles pour tenir debout seules, mais elles ressemblent aussi à des fondations pour ce qui arrive.</p>
<h2 id="les-propriétés-typées">Les propriétés typées</h2>
<p>C&rsquo;est la grande nouveauté. Depuis PHP 7.0, on pouvait typer les paramètres de fonctions et les valeurs de retour. Mais les propriétés de classe ? Toujours non typées :</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:#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">public</span> <span style="color:#f92672">?</span><span style="color:#a6e22e">DateTimeInterface</span> $deletedAt;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>7.4 change ça. Les propriétés typées font respecter les types à l&rsquo;affectation, pas seulement au niveau des sites d&rsquo;appel. Les classes deviennent auto-documentées d&rsquo;une façon que les docblocks n&rsquo;ont jamais vraiment réussi à faire, et le moteur attrape les erreurs de type avant qu&rsquo;elles ne se propagent dans la moitié de la stack.</p>
<p>Une subtilité : les propriétés typées sont <code>uninitialized</code> par défaut (pas <code>null</code>). Accéder à une propriété non initialisée lève une <code>Error</code>. C&rsquo;est un piège classique : <code>?string</code> n&rsquo;implique pas un défaut de <code>null</code>. Il faut encore un <code>= null</code> explicite pour ça.</p>
<h2 id="les-arrow-functions">Les arrow functions</h2>
<p>Les closures en PHP ont toujours nécessité d&rsquo;importer explicitement les variables de la portée extérieure avec <code>use</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>$multiplier <span style="color:#f92672">=</span> <span style="color:#ae81ff">3</span>;
</span></span><span style="display:flex;"><span>$fn <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $x <span style="color:#f92672">*</span> $multiplier; <span style="color:#75715e">// pas besoin de use()
</span></span></span></code></pre></div><p>Les arrow functions capturent automatiquement la portée englobante. Expression unique, retour implicite, pas de boilerplate. Elles ne remplacent pas les closures complètes pour la logique complexe, mais pour les callbacks courts, elles éliminent une catégorie de bruit qui s&rsquo;accumulait depuis des années.</p>
<h2 id="le-préchargement-opcache">Le préchargement opcache</h2>
<p>Pour les setups PHP-FPM à longue durée de vie, le préchargement permet à un script de charger et compiler des fichiers PHP en mémoire opcache au démarrage du serveur. Ces fichiers sont disponibles pour toutes les requêtes sans overhead de compilation.</p>
<p>Le gain varie selon l&rsquo;application. Sur les grands frameworks où les mêmes fichiers sont chargés à chaque requête, c&rsquo;est réel. Sur les petites applications, négligeable. Vaut la peine de benchmarker avant d&rsquo;ajouter la complexité de configuration.</p>
<h2 id="les-petites-choses-qui-saccumulent">Les petites choses qui s&rsquo;accumulent</h2>
<p>Les fonctionnalités mentionnées en passant méritent plus qu&rsquo;une ligne. L&rsquo;opérateur d&rsquo;affectation null-coalescente <code>??=</code> résout un pattern suffisamment agaçant à écrire à chaque fois, mais jamais assez pour se donner la peine de l&rsquo;abstraire :</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>$config[<span style="color:#e6db74">&#39;timeout&#39;</span>] <span style="color:#f92672">??=</span> <span style="color:#ae81ff">30</span>;
</span></span><span style="display:flex;"><span><span style="color:#75715e">// équivalent à : $config[&#39;timeout&#39;] = $config[&#39;timeout&#39;] ?? 30;
</span></span></span></code></pre></div><p>L&rsquo;opérateur spread dans les littéraux de tableau fait ce qu&rsquo;on attend de la version pour les appels de fonctions — dépacker un itérable dans un littéral de tableau :</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;blue&#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>$options <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:#f92672">...</span>$defaults, <span style="color:#e6db74">&#39;weight&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#ae81ff">1.2</span>];
</span></span><span style="display:flex;"><span><span style="color:#75715e">// [&#39;size&#39; =&gt; &#39;M&#39;, &#39;color&#39; =&gt; &#39;blue&#39;, &#39;weight&#39; =&gt; 1.2]
</span></span></span></code></pre></div><p>Note : les clés string n&rsquo;étaient pas supportées dans 7.4 pour le dépaquet de tableau. Ça viendra plus tard.</p>
<p>Les types de retour covariants et les types de paramètres contravariants comblent un vide qui rendait certains patterns d&rsquo;héritage inutilement maladroits. Une classe enfant peut maintenant affiner son type de retour vers un sous-type de celui du parent, sans erreur fatale :</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">Producer</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:#f92672">:</span> <span style="color:#a6e22e">Iterator</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">ChildProducer</span> <span style="color:#66d9ef">extends</span> <span style="color:#a6e22e">Producer</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:#f92672">:</span> <span style="color:#a6e22e">ArrayIterator</span> {} <span style="color:#75715e">// ArrayIterator implémente Iterator
</span></span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="lire-des-nombres-à-3h-du-matin">Lire des nombres à 3h du matin</h2>
<p>Le séparateur de littéraux numériques est une de ces fonctionnalités dont on ne sait pas qu&rsquo;on la voulait jusqu&rsquo;à la première fois qu&rsquo;on écrit une grande constante et qu&rsquo;on perd immédiatement le sens de l&rsquo;ordre de grandeur :</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>$earthMass    <span style="color:#f92672">=</span> <span style="color:#ae81ff">5_972_168_000_000_000_000_000_000</span>; <span style="color:#75715e">// kg
</span></span></span><span style="display:flex;"><span>$lightSpeed   <span style="color:#f92672">=</span> <span style="color:#ae81ff">299_792_458</span>;                        <span style="color:#75715e">// m/s
</span></span></span><span style="display:flex;"><span>$planck       <span style="color:#f92672">=</span> <span style="color:#ae81ff">6.626</span><span style="color:#a6e22e">_070_15e</span><span style="color:#f92672">-</span><span style="color:#ae81ff">34</span>;                  <span style="color:#75715e">// J·s
</span></span></span><span style="display:flex;"><span>$hexMask      <span style="color:#f92672">=</span> <span style="color:#ae81ff">0xFF_EC_D5_08</span>;
</span></span><span style="display:flex;"><span>$binaryFlags  <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b0001_1111_0010_0000</span>;
</span></span></code></pre></div><p>L&rsquo;underscore est purement syntaxique. Le moteur le supprime avant de parser la valeur. On peut le mettre n&rsquo;importe où entre les chiffres, bien que la convention suive le groupement naturel du système numérique utilisé.</p>
<h2 id="référencer-sans-posséder">Référencer sans posséder</h2>
<p><code>WeakReference</code> permet de tenir une référence à un objet sans empêcher le ramasse-miettes de le détruire. Le cas d&rsquo;usage : les caches et registres — on veut savoir qu&rsquo;un objet est vivant, mais on ne veut pas être la raison qu&rsquo;il reste vivant :</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>$object <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">HeavyObject</span>();
</span></span><span style="display:flex;"><span>$ref <span style="color:#f92672">=</span> <span style="color:#a6e22e">WeakReference</span><span style="color:#f92672">::</span><span style="color:#a6e22e">create</span>($object);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">var_dump</span>($ref<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">get</span>()); <span style="color:#75715e">// object(HeavyObject)
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">unset</span>($object);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">var_dump</span>($ref<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">get</span>()); <span style="color:#75715e">// NULL — le GC l&#39;a collecté
</span></span></span></code></pre></div><p>Avant 7.4, il y avait <code>WeakRef</code> via une extension, et certains frameworks faisaient des tours de passe-passe avec <code>SplObjectStorage</code> qui ne se comportaient pas tout à fait pareil. La classe native est juste directe.</p>
<h2 id="la-sérialisation-sans-surprise">La sérialisation sans surprise</h2>
<p>La sérialisation personnalisée d&rsquo;objets avant 7.4 passait par l&rsquo;interface <code>Serializable</code> : implémenter <code>serialize()</code> et <code>unserialize()</code>, retourner une string, reconstruire depuis elle. Le problème est que <code>serialize()</code> déclenchait <code>__sleep()</code>, <code>unserialize()</code> déclenchait <code>__wakeup()</code>, et l&rsquo;interaction entre ces hooks était fragile, surtout dans les hiérarchies d&rsquo;héritage.</p>
<p>7.4 introduit <code>__serialize()</code> et <code>__unserialize()</code>, qui travaillent avec des tableaux plutôt que des strings et n&rsquo;interagissent pas avec les anciens hooks :</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">Session</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">string</span> $token;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">\DateTime</span> $createdAt;
</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">__serialize</span>()<span style="color:#f92672">:</span> <span style="color:#66d9ef">array</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> [<span style="color:#e6db74">&#39;token&#39;</span> <span style="color:#f92672">=&gt;</span> $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">token</span>, <span style="color:#e6db74">&#39;created&#39;</span> <span style="color:#f92672">=&gt;</span> $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">createdAt</span><span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">getTimestamp</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">__unserialize</span>(<span style="color:#66d9ef">array</span> $data)<span style="color:#f92672">:</span> <span style="color:#a6e22e">void</span> {
</span></span><span style="display:flex;"><span>        $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">token</span> <span style="color:#f92672">=</span> $data[<span style="color:#e6db74">&#39;token&#39;</span>];
</span></span><span style="display:flex;"><span>        $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">createdAt</span> <span style="color:#f92672">=</span> (<span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\DateTime</span>())<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">setTimestamp</span>($data[<span style="color:#e6db74">&#39;created&#39;</span>]);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Quand les nouvelles et anciennes méthodes coexistent sur la même classe, <code>__serialize()</code> gagne. L&rsquo;ancienne interface <code>Serializable</code> est dépréciée dans 8.1.</p>
<h2 id="ce-que-la-bibliothèque-standard-a-discrètement-reçu">Ce que la bibliothèque standard a discrètement reçu</h2>
<p><code>mb_str_split()</code> fait ce que <code>str_split()</code> fait mais correctement pour les strings multibyte. Le manque était franchement embarrassant pour un langage utilisé dans autant de locales que PHP :</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">mb_str_split</span>(<span style="color:#e6db74">&#39;héllo&#39;</span>, <span style="color:#ae81ff">1</span>); <span style="color:#75715e">// [&#39;h&#39;, &#39;é&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;]
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">str_split</span>(<span style="color:#e6db74">&#39;héllo&#39;</span>, <span style="color:#ae81ff">1</span>);    <span style="color:#75715e">// [&#39;h&#39;, &#39;Ã&#39;, &#39;©&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;] — cassé
</span></span></span></code></pre></div><p><code>strip_tags()</code> accepte maintenant un tableau de tags autorisés, ce qui est plus propre que le format string qu&rsquo;il fallait passer auparavant :</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">strip_tags</span>($html, [<span style="color:#e6db74">&#39;p&#39;</span>, <span style="color:#e6db74">&#39;br&#39;</span>, <span style="color:#e6db74">&#39;strong&#39;</span>]); <span style="color:#75715e">// était : &#39;&lt;p&gt;&lt;br&gt;&lt;strong&gt;&#39;
</span></span></span></code></pre></div><p><code>proc_open()</code> accepte maintenant un tableau de commandes, contournant complètement l&rsquo;interprétation par le shell. Même idée que <code>subprocess</code> de Python avec <code>shell=False</code>. À retenir quand on passe des arguments fournis par l&rsquo;utilisateur à un processus externe.</p>
<h2 id="le-chapitre-ffi">Le chapitre FFI</h2>
<p>L&rsquo;extension Foreign Function Interface a atterri dans 7.4 après avoir passé du temps dans une branche feature. Elle permet à PHP d&rsquo;appeler des fonctions C natives en chargeant une bibliothèque partagée et en déclarant 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>$ffi <span style="color:#f92672">=</span> <span style="color:#a6e22e">FFI</span><span style="color:#f92672">::</span><span style="color:#a6e22e">cdef</span>(<span style="color:#e6db74">&#34;int strlen(const char *s);&#34;</span>, <span style="color:#e6db74">&#34;libc.so.6&#34;</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">var_dump</span>($ffi<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">strlen</span>(<span style="color:#e6db74">&#34;hello&#34;</span>)); <span style="color:#75715e">// int(5)
</span></span></span></code></pre></div><p>Les applications pratiques sont étroites mais réelles : appeler des API de plateforme sans binding PHP, wrapper du code C critique pour les performances sans écrire une extension complète, ou juste jouer avec des bibliothèques natives directement. Ce n&rsquo;est pas un remplacement des extensions propres en production, mais ça supprime la barrière &ldquo;écrire une extension C&rdquo; pour l&rsquo;exploration.</p>
<h2 id="ce-qui-a-été-déprécié">Ce qui a été déprécié</h2>
<p>Quelques choses qui auraient dû être nettoyées depuis longtemps ont finalement reçu le traitement dépréciation dans 7.4.</p>
<p>Les ternaires imbriqués sans parenthèses ont toujours été ambigus. PHP les évaluait de gauche à droite alors que pratiquement tous les autres langages avec un ternaire évaluent de droite à gauche :</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">// Était ambigu, maintenant déprécié :
</span></span></span><span style="display:flex;"><span>$a <span style="color:#f92672">?</span> $b <span style="color:#f92672">:</span> $c <span style="color:#f92672">?</span> $d <span style="color:#f92672">:</span> $e;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Rendre explicite :
</span></span></span><span style="display:flex;"><span>($a <span style="color:#f92672">?</span> $b <span style="color:#f92672">:</span> $c) <span style="color:#f92672">?</span> $d <span style="color:#f92672">:</span> $e;
</span></span></code></pre></div><p>L&rsquo;accès par offset avec accolades pour les strings et tableaux — <code>$str{0}</code> au lieu de <code>$str[0]</code> — est déprécié et supprimé dans 8.0. C&rsquo;était toujours un alias, jamais une fonctionnalité distincte.</p>
<p><code>implode()</code> avec l&rsquo;ordre d&rsquo;arguments inversé (tableau en premier, colle en second) est déprécié. La fonction a accepté les deux ordres depuis le début, ce qui était une erreur. L&rsquo;ordre correct est <code>implode(string $separator, array $array)</code>.</p>
<h2 id="ce-qui-arrive-ensuite">Ce qui arrive ensuite</h2>
<p>7.4 est la dernière version 7.x. Les dépréciations sont principalement du déblayage pour les suppressions dans 8.0. Le backlog de RFCs pour 8.0 est substantiel : JIT, attributs, arguments nommés, expressions match. 7.4 est un bon endroit où atterrir en attendant que tout ça arrive.</p>
]]></content:encoded></item><item><title>PHP 7.0 : performances, types, et les fonctionnalités qui ont marqué</title><link>https://guillaumedelre.github.io/fr/2016/01/17/php-7.0-performances-types-et-les-fonctionnalit%C3%A9s-qui-ont-marqu%C3%A9/</link><pubDate>Sun, 17 Jan 2016 00:00:00 +0000</pubDate><guid>https://guillaumedelre.github.io/fr/2016/01/17/php-7.0-performances-types-et-les-fonctionnalit%C3%A9s-qui-ont-marqu%C3%A9/</guid><description>Part 1 of 11 in &amp;quot;Sorties PHP&amp;quot;: PHP 7.0 a doublé les performances grâce à une réécriture du Zend Engine et apporté enfin les type hints scalaires au langage.</description><category>php-releases</category><content:encoded><![CDATA[<p>PHP 7.0 est sorti le 3 décembre. Un mois et demi plus tard, j&rsquo;ai migré deux projets et les résultats sont difficiles à ignorer.</p>
<p>Le chiffre phare : 2x plus rapide que PHP 5.6. Ce n&rsquo;est pas un benchmark cherry-pick — c&rsquo;est la médiane sur des applications réelles. Le Zend Engine a été réécrit pour utiliser une nouvelle représentation interne des valeurs, ce qui réduit significativement l&rsquo;utilisation mémoire et diminue les allocations. Sur un projet, le temps de réponse moyen a chuté de 40% sans aucune modification du code. On met à jour, et ça va plus vite.</p>
<p>Mais les performances ne sont pas la partie la plus intéressante.</p>
<h2 id="les-types-enfin">Les types, enfin</h2>
<p>PHP a eu les type hints pour les objets depuis la 5.0, pour les tableaux depuis la 5.1. En 7.0, on peut enfin déclarer des types scalaires pour les paramètres de fonctions et les valeurs de retour :</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">add</span>(<span style="color:#a6e22e">int</span> $a, <span style="color:#a6e22e">int</span> $b)<span style="color:#f92672">:</span> <span style="color:#a6e22e">int</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> $a <span style="color:#f92672">+</span> $b;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>En mode strict (<code>declare(strict_types=1)</code>), passer un float à cette fonction lève une <code>TypeError</code>. En mode coercitif par défaut, PHP convertit la valeur. Cette distinction compte : le mode strict est par fichier, on peut donc l&rsquo;adopter progressivement sans tout casser d&rsquo;un coup.</p>
<p>Les déclarations de type de retour constituent l&rsquo;autre moitié. Placer l&rsquo;intention dans la signature plutôt que dans un docblock signifie que c&rsquo;est le moteur qui l&rsquo;applique, pas un code reviewer à moitié endormi.</p>
<h2 id="lopérateur-null-coalescent">L&rsquo;opérateur null coalescent</h2>
<p><code>??</code> est petit mais utilisé en permanence :</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>$username <span style="color:#f92672">=</span> $_GET[<span style="color:#e6db74">&#39;user&#39;</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;guest&#39;</span>;
</span></span></code></pre></div><p>Ça remplace <code>isset($_GET['user']) ? $_GET['user'] : 'guest'</code>. Il se chaîne aussi : <code>$a ?? $b ?? $c</code>. Après des années de bruit avec <code>isset()</code>, ça seul valait la mise à jour.</p>
<h2 id="la-partie-qui-casse">La partie qui casse</h2>
<p>La refonte de la gestion des erreurs est le vrai risque lors de la migration. Beaucoup d&rsquo;erreurs fatales sont maintenant des exceptions <code>Error</code>, attrapables mais différentes des <code>Exception</code>. Le code qui comptait sur les erreurs fatales pour stopper l&rsquo;exécution silencieusement a maintenant besoin d&rsquo;une gestion explicite. La suppression d&rsquo;erreurs avec <code>@</code> fonctionne aussi différemment par endroits.</p>
<p>Lire le guide de migration avant de toucher une appli en production. Le gain est réel, mais le fossé entre 5.6 et 7.0 est le plus large que PHP ait jamais eu.</p>
<h2 id="lopérateur-vaisseau-spatial">L&rsquo;opérateur vaisseau spatial</h2>
<p><code>&lt;=&gt;</code> est un opérateur de comparaison combiné qui retourne -1, 0 ou 1. Il est surtout là pour le tri :</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">usort</span>($users, <span style="color:#66d9ef">function</span> ($a, $b) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> $a<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">age</span> <span style="color:#f92672">&lt;=&gt;</span> $b<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">age</span>;
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>Avant ça, un comparateur de tri personnalisé était un petit exercice de mémoire arithmétique. <code>$a - $b</code> fonctionne pour les entiers mais plante silencieusement pour les flottants. <code>&lt;=&gt;</code> fait ce qu&rsquo;il faut pour chaque type comparable.</p>
<h2 id="les-classes-anonymes">Les classes anonymes</h2>
<p>On peut maintenant instancier une classe définie en ligne, sur le moment, sans lui donner de nom :</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>$logger <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">class</span>($config) <span style="color:#66d9ef">implements</span> <span style="color:#a6e22e">LoggerInterface</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 style="color:#66d9ef">private</span> <span style="color:#66d9ef">array</span> $config) {}
</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">log</span>(<span style="color:#a6e22e">string</span> $message)<span style="color:#f92672">:</span> <span style="color:#a6e22e">void</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">file_put_contents</span>($this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">config</span>[<span style="color:#e6db74">&#39;path&#39;</span>], $message <span style="color:#f92672">.</span> <span style="color:#a6e22e">PHP_EOL</span>, <span style="color:#a6e22e">FILE_APPEND</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>Le cas d&rsquo;usage canonique, ce sont les doublures de test et les implémentations d&rsquo;interface ponctuelles qui ne méritent pas un fichier. Ça supprime une vraie friction : le fossé entre &ldquo;j&rsquo;ai besoin d&rsquo;un objet&rdquo; et &ldquo;je dois créer un fichier de classe pour un truc de 10 lignes&rdquo;.</p>
<h2 id="aléatoire-cryptographiquement-sûr">Aléatoire cryptographiquement sûr</h2>
<p>Les <code>rand()</code> et <code>mt_rand()</code> de PHP 5 n&rsquo;ont jamais été conçus pour la sécurité. La 7.0 ajoute deux fonctions qui le sont :</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>$token <span style="color:#f92672">=</span> <span style="color:#a6e22e">bin2hex</span>(<span style="color:#a6e22e">random_bytes</span>(<span style="color:#ae81ff">32</span>)); <span style="color:#75715e">// token hexadécimal de 64 caractères
</span></span></span><span style="display:flex;"><span>$pin   <span style="color:#f92672">=</span> <span style="color:#a6e22e">random_int</span>(<span style="color:#ae81ff">100000</span>, <span style="color:#ae81ff">999999</span>);
</span></span></code></pre></div><p><code>random_bytes()</code> puise dans le CSPRNG du système d&rsquo;exploitation. <code>random_int()</code> enveloppe ça pour les entiers. Ces fonctions remplacent tous les schémas de génération de tokens maison qui faisaient ça mal en silence, ce qui représente la majorité d&rsquo;entre eux.</p>
<h2 id="les-déclarations-use-groupées">Les déclarations use groupées</h2>
<p>Avant 7.0, importer cinq éléments depuis le même namespace nécessitait cinq instructions <code>use</code>. Maintenant :</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">use</span> <span style="color:#a6e22e">App\Model\</span>{<span style="color:#a6e22e">User</span>, <span style="color:#a6e22e">Order</span>, <span style="color:#a6e22e">Product</span>};
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">use</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">App\Helpers\</span>{<span style="color:#a6e22e">formatDate</span>, <span style="color:#a6e22e">slugify</span>};
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">use</span> <span style="color:#66d9ef">const</span> <span style="color:#66d9ef">App\Config\</span>{<span style="color:#a6e22e">MAX_RETRIES</span>, <span style="color:#a6e22e">TIMEOUT</span>};
</span></span></code></pre></div><p>Petite amélioration ergonomique, mais qui réduit le bruit visuel en haut des fichiers avec des hiérarchies de namespaces profondes.</p>
<h2 id="les-générateurs-ont-grandi">Les générateurs ont grandi</h2>
<p>Les générateurs en 5.5 étaient intéressants mais incomplets. La 7.0 ajoute deux choses. Premièrement, un générateur peut maintenant avoir une valeur de retour, accessible après la fin de l&rsquo;itération :</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:#f92672">:</span> <span style="color:#a6e22e">Generator</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">yield</span> <span style="color:#e6db74">&#39;step 1&#39;</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">yield</span> <span style="color:#e6db74">&#39;step 2&#39;</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#39;done&#39;</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$gen <span style="color:#f92672">=</span> <span style="color:#a6e22e">process</span>();
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($gen <span style="color:#66d9ef">as</span> $step) { <span style="color:#75715e">/* ... */</span> }
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $gen<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">getReturn</span>(); <span style="color:#75715e">// &#34;done&#34;
</span></span></span></code></pre></div><p>Deuxièmement, <code>yield from</code> délègue à un autre générateur ou itérable, en transmettant transparemment les valeurs et valeurs de retour :</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">inner</span>()<span style="color:#f92672">:</span> <span style="color:#a6e22e">Generator</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">yield</span> <span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">yield</span> <span style="color:#ae81ff">2</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#39;inner done&#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">outer</span>()<span style="color:#f92672">:</span> <span style="color:#a6e22e">Generator</span> {
</span></span><span style="display:flex;"><span>    $result <span style="color:#f92672">=</span> <span style="color:#66d9ef">yield</span> <span style="color:#a6e22e">from</span> <span style="color:#a6e22e">inner</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">echo</span> $result; <span style="color:#75715e">// &#34;inner done&#34;
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">yield</span> <span style="color:#ae81ff">3</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Ça rend la composition de générateurs pratique sans avoir à câbler manuellement les valeurs entre eux.</p>
<h2 id="closurecall">Closure::call()</h2>
<p>Une façon plus directe de lier une closure à un objet et de l&rsquo;appeler immédiatement :</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">Counter</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">int</span> $count <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$increment <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span> (<span style="color:#a6e22e">int</span> $by)<span style="color:#f92672">:</span> <span style="color:#a6e22e">void</span> {
</span></span><span style="display:flex;"><span>    $this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">count</span> <span style="color:#f92672">+=</span> $by;
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$increment<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">call</span>(<span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Counter</span>(), <span style="color:#ae81ff">5</span>);
</span></span></code></pre></div><p><code>bindTo()</code> existait avant mais nécessitait deux étapes. <code>call()</code> les fusionne et est plus rapide à l&rsquo;exécution car il évite la création d&rsquo;une closure intermédiaire.</p>
<h2 id="syntaxe-déchappement-unicode-dans-les-chaînes">Syntaxe d&rsquo;échappement Unicode dans les chaînes</h2>
<p>On peut maintenant intégrer des caractères Unicode directement dans les chaînes entre guillemets doubles ou les heredocs via un point de 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">echo</span> <span style="color:#e6db74">&#34;\u{1F418}&#34;</span>; <span style="color:#75715e">// 🐘
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;\u{00E9}&#34;</span>;  <span style="color:#75715e">// é
</span></span></span></code></pre></div><p>C&rsquo;est mieux que de copier-coller des caractères depuis une table Unicode dans les fichiers sources, ce que les gens faisaient vraiment.</p>
<h2 id="un-unserialize-plus-sûr">Un unserialize() plus sûr</h2>
<p><code>unserialize()</code> a une longue histoire d&rsquo;être un vecteur d&rsquo;attaques par injection d&rsquo;objets. La 7.0 ajoute une option <code>allowed_classes</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>$data <span style="color:#f92672">=</span> <span style="color:#a6e22e">unserialize</span>($input, [<span style="color:#e6db74">&#39;allowed_classes&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">false</span>]);
</span></span><span style="display:flex;"><span>$data <span style="color:#f92672">=</span> <span style="color:#a6e22e">unserialize</span>($input, [<span style="color:#e6db74">&#39;allowed_classes&#39;</span> <span style="color:#f92672">=&gt;</span> [<span style="color:#a6e22e">User</span><span style="color:#f92672">::</span><span style="color:#a6e22e">class</span>, <span style="color:#a6e22e">Order</span><span style="color:#f92672">::</span><span style="color:#a6e22e">class</span>]]);
</span></span></code></pre></div><p>Passer <code>false</code> empêche toute instanciation d&rsquo;objet pendant la désérialisation. C&rsquo;est le comportement par défaut à adopter quand on désérialise des données non fiables.</p>
<h2 id="1234-division-entière">:1234: Division entière</h2>
<p><code>intdiv()</code> est une division entière explicite sans intermédiaire flottant :</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>$pages <span style="color:#f92672">=</span> <span style="color:#a6e22e">intdiv</span>(<span style="color:#a6e22e">count</span>($items), $perPage); <span style="color:#75715e">// int, pas besoin de cast
</span></span></span></code></pre></div><p>Oui, on pourrait caster le résultat d&rsquo;une division. <code>intdiv()</code> rend l&rsquo;intention claire et évite les cas limites de précision flottante que le cast introduit pour les grands nombres.</p>
<h2 id="les-constantes-en-tableaux">Les constantes en tableaux</h2>
<p>Avant 7.0, <code>define()</code> n&rsquo;acceptait que les valeurs scalaires. Les tableaux fonctionnaient avec <code>const</code> au niveau de la classe ou du namespace mais pas avec <code>define()</code>. Maintenant si :</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">define</span>(<span style="color:#e6db74">&#39;HTTP_METHODS&#39;</span>, [<span style="color:#e6db74">&#39;GET&#39;</span>, <span style="color:#e6db74">&#39;POST&#39;</span>, <span style="color:#e6db74">&#39;PUT&#39;</span>, <span style="color:#e6db74">&#39;DELETE&#39;</span>, <span style="color:#e6db74">&#39;PATCH&#39;</span>]);
</span></span></code></pre></div><p>Utile pour la configuration qui doit être une constante mais qui vit en dehors d&rsquo;une classe.</p>
<h2 id="des-assertions-avec-des-dents">Des assertions avec des dents</h2>
<p><code>assert()</code> a reçu une vraie refonte. En PHP 5, les assertions étaient un eval de chaînes à l&rsquo;exécution. Maintenant elles peuvent lever des exceptions et être complètement supprimées en production avec zéro overhead :</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 php.ini ou au bootstrap :
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// assert.active = 1 (dev), 0 (prod)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// assert.exception = 1
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>($user<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">isVerified</span>(), <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\LogicException</span>(<span style="color:#e6db74">&#39;Unverified user reached checkout&#39;</span>));
</span></span></code></pre></div><p>Quand <code>assert.active = 0</code>, l&rsquo;expression n&rsquo;est jamais évaluée. Quand c&rsquo;est activé, une assertion qui échoue lève directement l&rsquo;exception fournie. C&rsquo;est enfin un outil qu&rsquo;on peut utiliser sans honte.</p>
<h2 id="la-refonte-de-session_start">La refonte de session_start()</h2>
<p><code>session_start()</code> accepte maintenant un tableau d&rsquo;options qui surchargent les directives <code>php.ini</code> pour cet appel :</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">session_start</span>([
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;cookie_lifetime&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#ae81ff">86400</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;cookie_secure&#39;</span>   <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;cookie_httponly&#39;</span>  <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;cookie_samesite&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;Lax&#39;</span>,
</span></span><span style="display:flex;"><span>]);
</span></span></code></pre></div><p>Avant ça, on définissait soit les options globalement dans <code>php.ini</code>, soit on appelait <code>ini_set()</code> avant <code>session_start()</code>. Aucune des deux n&rsquo;était top quand on avait besoin de configurations de session différentes dans différentes parties d&rsquo;une appli.</p>
]]></content:encoded></item></channel></rss>