{"id":47870,"date":"2021-09-24T15:09:11","date_gmt":"2021-09-24T13:09:11","guid":{"rendered":"https:\/\/kinsta.com\/?p=100177"},"modified":"2023-03-14T14:35:01","modified_gmt":"2023-03-14T13:35:01","slug":"traspiling-php","status":"publish","type":"post","link":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/","title":{"rendered":"Guida Definitiva al Transpiling del Codice PHP"},"content":{"rendered":"<p>In circostanze ideali, dovremmo usare <a href=\"https:\/\/kinsta.com\/it\/changelog\/php-8\/\">PHP 8.0<\/a> (l&#8217;ultima versione al momento in cui scriviamo questo articolo) per tutti i nostri siti e aggiornarlo non appena viene rilasciata una nuova versione. Tuttavia, gli sviluppatori avranno spesso bisogno di lavorare con precedenti versioni di PHP, come quando si crea un plugin pubblico per <a href=\"https:\/\/kinsta.com\/it\/blog\/cosa-e-wordpress\/\">WordPress<\/a> o si lavora con codice legacy che impedisce di aggiornare l&#8217;ambiente del webserver.<\/p>\n<p>In queste situazioni, potremmo abbandonare la speranza di utilizzare il pi\u00f9 recente codice PHP. Ma c&#8217;\u00e8 un&#8217;alternativa migliore: possiamo ancora scrivere il nostro codice sorgente con PHP 8.0 e tradurlo in una versione precedente di PHP &#8211; anche in PHP 7.1.<\/p>\n<p>In questa guida spiegheremo tutto quello che c&#8217;\u00e8 da sapere sul transpiling del codice PHP.<\/p>\n<div><\/div><kinsta-auto-toc heading=\"Table of Contents\" exclude=\"last\" list-style=\"arrow\" selector=\"h2\" count-number=\"-1\"><\/kinsta-auto-toc>\n<h2>Cos&#8217;\u00e8 il Transpiling?<\/h2>\n<p>Il transpiling converte il codice sorgente di un <a href=\"https:\/\/kinsta.com\/it\/blog\/miglior-linguaggio-di-programmazione\/\">linguaggio di programmazione<\/a> in un codice sorgente equivalente dello stesso o di un diverso linguaggio di programmazione.<\/p>\n<p>La compilazione non \u00e8 un concetto nuovo nello sviluppo web: gli sviluppatori lato client avranno probabilmente familiarit\u00e0 con <a href=\"https:\/\/babeljs.io\/\" target=\"_blank\" rel=\"noopener noreferrer\">Babel<\/a>, un transpiler per il codice JavaScript.<\/p>\n<p>Babel converte il codice JavaScript dalla moderna versione ECMAScript 2015+ in una versione legacy compatibile con i vecchi browser. Ad esempio, data una arrow function ES2015:<\/p>\n<pre><code class=\"language-js\">[2, 4, 6].map((n) =&gt; n * 2);\n<\/code><\/pre>\n<p>&#8230;Babel la convertir\u00e0 nella sua versione ES5:<\/p>\n<pre><code class=\"language-js\">[2, 4, 6].map(function(n) {\n  return n * 2;\n});<\/code><\/pre>\n<h3>Che cos&#8217;\u00e8 il Transpiling di PHP?<\/h3>\n<p>Ci\u00f2 che forse \u00e8 nuovo nello sviluppo web \u00e8 la possibilit\u00e0 di effettuare il transpiling del codice lato server, in particolare di PHP.<\/p>\n<p>Il transpiling di PHP funziona allo stesso modo del transpiling di JavaScript: il codice sorgente di una <a href=\"https:\/\/kinsta.com\/it\/blog\/versioni-php\/\">versione moderna di PHP<\/a> viene convertito in un codice equivalente per una vecchia versione di PHP.<\/p>\n<p>Seguendo lo stesso esempio di prima, una arrow function da PHP 7.4:<\/p>\n<pre><code class=\"language-php\">$nums = array_map(fn($n) =&gt; $n * 2, [2, 4, 6]);\n<\/code><\/pre>\n<p>&#8230;pu\u00f2 essere trasformata nella sua versione equivalente in PHP 7.3:<\/p>\n<pre><code class=\"language-php\">$nums = array_map(\n  function ($n) {\n    return $n * 2;\n  },\n  [2, 4, 6]\n);<\/code><\/pre>\n<p>Le arrow function possono essere oggetto di traspiling perch\u00e9 sono <a href=\"https:\/\/en.wikipedia.org\/wiki\/Syntactic_sugar\" target=\"_blank\" rel=\"noopener noreferrer\">syntactic sugar<\/a>, cio\u00e8 una nuova sintassi per produrre un comportamento esistente. Questo \u00e8 il beneficio maggiore.<\/p>\n<p>Ma ci sono anche nuove funzioni che creano un nuovo comportamento e, come tali, non ci sar\u00e0 un codice equivalente per le versioni precedenti di PHP. \u00c8 il caso dei <a href=\"https:\/\/kinsta.com\/it\/blog\/php-8\/#union-types-2-0\">tipi unione<\/a>, introdotti in PHP 8.0:<\/p>\n<pre><code class=\"language-php\">function someFunction(float|int $param): string|float|int|null\n{\n  \/\/ ...\n}<\/code><\/pre>\n<p>In queste situazioni, il transpiling pu\u00f2 comunque essere eseguito finch\u00e9 la nuova funzionalit\u00e0 \u00e8 richiesta per lo sviluppo e non per la produzione. Poi, possiamo semplicemente rimuovere del tutto la funzionalit\u00e0 dal codice oggetto di transpiling senza gravi conseguenze.<\/p>\n<p>Uno di questi esempi sono i tipi unione. Questa funzionalit\u00e0 permette di controllare che non ci sia una mancata corrispondenza tra il tipo di input e il suo valore fornito, il che aiuta a prevenire i bug. Se c&#8217;\u00e8 un conflitto con i tipi, ci sar\u00e0 un errore gi\u00e0 nello sviluppo e dovremmo correggerlo prima che il codice raggiunga la produzione.<\/p>\n<p>Quindi, possiamo permetterci di rimuovere la funzionalit\u00e0 dal codice per la produzione:<\/p>\n<pre><code class=\"language-php\">function someFunction($param)\n{\n  \/\/ ...\n}<\/code><\/pre>\n<p>Se l&#8217;errore si verifica ancora in produzione, il messaggio di errore lanciato sar\u00e0 meno preciso che se avessimo i tipi unione. Tuttavia, questo possibile svantaggio \u00e8 superato in primo luogo dall&#8217;essere in grado di utilizzare i tipi unione.<\/p>\n\n<h2>Vantaggi del Transpiling del Codice PHP<\/h2>\n<p>Il transpiling permette di creare il codice di un&#8217;applicazione utilizzando l&#8217;ultima versione di PHP e produrre una versione che funziona anche in ambienti che eseguono vecchie versioni di PHP.<\/p>\n<p>Questo pu\u00f2 essere particolarmente utile per gli sviluppatori che creano prodotti per <a href=\"https:\/\/kinsta.com\/it\/blog\/content-management-system\/\">sistemi di gestione dei contenuti (CMS)<\/a> legacy. WordPress, per esempio, <a href=\"https:\/\/wordpress.org\/about\/requirements\/\" target=\"_blank\" rel=\"noopener noreferrer\">supporta<\/a> ancora <a href=\"https:\/\/wordpress.org\/about\/requirements\/\" target=\"_blank\" rel=\"noopener noreferrer\">ufficialmente PHP 5.6<\/a> (anche se raccomanda PHP 7.4+). La percentuale di siti WordPress che eseguono le versioni PHP da 5.6 a 7.2 &#8211; che sono tutte End-of-Life (EOL), il che significa che non ricevono pi\u00f9 aggiornamenti di sicurezza &#8211; si attesta su un considerevole 34,8%, e quelli che eseguono qualsiasi versione di PHP diversa dalla 8.0 si attesta su un enorme 99,5%:<\/p>\n<figure style=\"width: 920px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/07\/wp-stats.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-full\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/07\/wp-stats.png\" alt=\"Statistiche sull'utilizzo di WordPress per versione.\" width=\"920\" height=\"720\"><\/a><figcaption class=\"wp-caption-text\">Statistiche sull&#8217;utilizzo di WordPress per versione. Fonte immagine: <a href=\"https:\/\/wordpress.org\/about\/stats\/\" target=\"_blank\" rel=\"noopener noreferrer\">WordPress<\/a><\/figcaption><\/figure>\n<p>Di conseguenza, i temi e i plugin di WordPress destinati ad un pubblico globale saranno molto probabilmente codificati con una vecchia versione di PHP per aumentarne la portata. Grazie al transpiling, questi potrebbero essere codificati utilizzando PHP 8.0, ed essere comunque rilasciati per una vecchia versione di PHP, raggiungendo cos\u00ec il maggior numero di utenti possibile.<\/p>\n<p>Infatti, qualsiasi applicazione che ha bisogno di supportare una qualsiasi versione di PHP diversa da quella pi\u00f9 recente (anche all&#8217;interno della gamma delle versioni PHP attualmente supportate) pu\u00f2 beneficiarne.<\/p>\n<p>Questo \u00e8 il caso di Drupal, che <a href=\"https:\/\/www.drupal.org\/docs\/system-requirements\/php-requirements\" target=\"_blank\" rel=\"noopener noreferrer\">richiede PHP 7.3<\/a>. Grazie al transpiling, gli sviluppatori possono creare moduli Drupal disponibili al pubblico utilizzando PHP 8.0 e rilasciarli con PHP 7.3.<\/p>\n<p>Un altro esempio \u00e8 quando si crea codice personalizzato per clienti che non possono eseguire PHP 8.0 nei loro ambienti per una ragione o per l&#8217;altra. Tuttavia, grazie al transpiling, gli sviluppatori possono sviluppare i propri prodotti usando PHP 8.0 ed eseguirli su quegli ambienti legacy.<\/p>\n<h3>Quando Effettuare il Transpiling di PHP<\/h3>\n<p>Il codice PHP pu\u00f2 sempre essere oggetto di transpiling, a meno che non contenga qualche funzionalit\u00e0 di PHP che non ha un equivalente nella versione precedente di PHP.<\/p>\n<p>Questo \u00e8 probabilmente il caso degli <a href=\"https:\/\/kinsta.com\/it\/blog\/php-8\/#attributes\">attributi<\/a>, introdotti in PHP 8.0:<\/p>\n<pre><code class=\"language-php\">#[SomeAttr]\nfunction someFunc() {}\n\n#[AnotherAttr]\nclass SomeClass {}<\/code><\/pre>\n<p>Nell&#8217;esempio precedente in cui si utilizzavano le arrow function, era possibile eseguire il transpiling perch\u00e9 le arrow function sono sintactic sugar. Gli attributi, al contrario, creano un comportamento completamente nuovo. Questo comportamento potrebbe anche essere riprodotto con PHP 7.4 e successivi, ma solo codificando manualmente, cio\u00e8 non automaticamente sulla base di uno strumento o di un processo (l&#8217;AI potrebbe fornire una soluzione, ma non ci siamo ancora).<\/p>\n<p>Gli attributi destinati allo sviluppo, come <a href=\"https:\/\/wiki.php.net\/rfc\/deprecated_attribute\"><code>#[Deprecated]<\/code><\/a>possono essere rimossi nello stesso modo in cui vengono rimossi i tipi unione. Ma gli attributi che modificano il comportamento dell&#8217;applicazione in produzione non possono essere rimossi e non possono nemmeno essere direttamente oggetto di transpiling.<\/p>\n<p>Ad oggi, nessun transpiler pu\u00f2 prendere del codice con attributi PHP 8.0 e produrre automaticamente il loro equivalente in PHP 7.4. Di conseguenza, se il vostro codice PHP ha bisogno di utilizzare gli attributi, allora il transpiling sar\u00e0 difficile o irrealizzabile.<\/p>\n<h3>Funzionalit\u00e0 di PHP che Possono Essere Oggetto di Transpiling<\/h3>\n<p>Queste sono le funzionalit\u00e0 di PHP 7.1 e superiori che possono essere attualmente oggetto di transpiling. Se il vostro codice utilizza solo queste funzionalit\u00e0, potete star certi che il transpiling della vostra applicazione funzioner\u00e0. Altrimenti, dovrete valutare se il codice codice oggetto di transpiling produce dei failure.<\/p>\n<table>\n<thead>\n<tr>\n<th>Versione PHP<\/th>\n<th>Funzionalit\u00e0<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>7.1<\/td>\n<td>Tutto<\/td>\n<\/tr>\n<tr>\n<td>7.2<\/td>\n<td>&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration72.new-features.php#migration72.new-features.object-type\" target=\"_blank\" rel=\"noopener noreferrer\">tipo object<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration72.new-features.php#migration72.new-features.param-type-widening\" target=\"_blank\" rel=\"noopener noreferrer\">ampliamento del tipo di parametro<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/function.preg-match.php#refsect1-function.preg-match-parameters\" target=\"_blank\" rel=\"noopener noreferrer\">Flag <code>PREG_UNMATCHED_AS_NULL<\/code> in <code>preg_match<\/code><\/a><\/td>\n<\/tr>\n<tr>\n<td>7.3<\/td>\n<td>&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration73.new-features.php#migration73.new-features.core.destruct-reference\" target=\"_blank\" rel=\"noopener noreferrer\">Assegnazioni di riferimento nella destrutturazione di <code>list()<\/code><\/a> \/ array<em>(eccetto all&#8217;interno di <code>foreach<\/code> &#8211; <a href=\"https:\/\/github.com\/rectorphp\/rector\/issues\/4376\" target=\"_blank\" rel=\"noopener noreferrer\">#4376<\/a><\/em>)<br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration73.new-features.php#migration73.new-features.core.heredoc\" target=\"_blank\" rel=\"noopener noreferrer\">Sintassi Heredoc e Nowdoc flessibile<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration73.new-features.php#migration73.new-features.core.trailing-commas\" target=\"_blank\" rel=\"noopener noreferrer\">Virgole finali nelle chiamate di funzioni<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration73.other-changes.php#migration73.other-changes.core.setcookie\" target=\"_blank\" rel=\"noopener noreferrer\"><code>set(raw)cookie<\/code> accetta l&#8217;argomento $option<\/a><\/td>\n<\/tr>\n<tr>\n<td>7.4<\/td>\n<td>&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration74.new-features.php#migration74.new-features.core.typed-properties\" target=\"_blank\" rel=\"noopener noreferrer\">Propriet\u00e0 tipizzate<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/functions.arrow.php\" target=\"_blank\" rel=\"noopener noreferrer\">Arrow function<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration74.new-features.php#migration74.new-features.core.null-coalescing-assignment-operator\" target=\"_blank\" rel=\"noopener noreferrer\">Operatore di assegnazione Null coalescente<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration74.new-features.php#migration74.new-features.core.unpack-inside-array\" target=\"_blank\" rel=\"noopener noreferrer\">Spacchettamento all&#8217;interno degli array<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration74.new-features.php#migration74.new-features.core.numeric-literal-separator\" target=\"_blank\" rel=\"noopener noreferrer\">Separatore di letterali numerici<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration74.new-features.php#migration74.new-features.standard.strip-tags\" target=\"_blank\" rel=\"noopener noreferrer\"><code>strip_tags()<\/code><\/a> con array di nomi di tag<br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration74.new-features.php#migration74.new-features.core.type-variance\" target=\"_blank\" rel=\"noopener noreferrer\">tipi di ritorno covarianti e tipi di param controvarianti<\/a><\/td>\n<\/tr>\n<tr>\n<td>8.0<\/td>\n<td>&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/union-types\" target=\"_blank\" rel=\"noopener noreferrer\">Tipi unione<\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/mixed-type\" target=\"_blank\" rel=\"noopener noreferrer\">pseudo tipo <code>mixed<\/code><\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/static-return-type\" target=\"_blank\" rel=\"noopener noreferrer\">tipo di ritorno <code>static<\/code><\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/class-constant-on-objects\" target=\"_blank\" rel=\"noopener noreferrer\"><code>::class<\/code><\/a> costante magica sugli oggetti<br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/match-expression\" target=\"_blank\" rel=\"noopener noreferrer\"><code>match<\/code><\/a> alle espressioni<br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/catch-exception-type\" target=\"_blank\" rel=\"noopener noreferrer\"><code>catch<\/code><\/a> le eccezioni solo per tipo<br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/null-safe-operator\" target=\"_blank\" rel=\"noopener noreferrer\">Operatore null-safe<\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/constructor-property-promotion\" target=\"_blank\" rel=\"noopener noreferrer\">Promozione delle propriet\u00e0 del costruttore di classe<\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/trailing-comma-parameter-use-list\" target=\"_blank\" rel=\"noopener noreferrer\">Virgole finali negli elenchi di parametri e negli elenchi di chiusure <code>use<\/code><\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Transpiler PHP<\/h2>\n<p>Attualmente, c&#8217;\u00e8 uno strumento per il transpiling del codice PHP: <a href=\"https:\/\/github.com\/rectorphp\/rector\">Rector<\/a>.<\/p>\n<p>Rector \u00e8 uno strumento di ricostruzione di PHP, che converte il codice basandosi su regole programmabili. Inseriamo il codice sorgente e l&#8217;<a href=\"https:\/\/github.com\/rectorphp\/rector\/blob\/main\/docs\/rector_rules_overview.md\" target=\"_blank\" rel=\"noopener noreferrer\">insieme di regole<\/a> da eseguire e Rector trasformer\u00e0 il codice.<\/p>\n<p>Rector viene utilizzato tramite linea di comando, installato nel progetto tramite Composer. Quando viene eseguito, Rector produce un &#8220;diff&#8221; (aggiunte in verde, rimozioni in rosso) del codice prima e dopo la conversione:<\/p>\n<figure style=\"width: 740px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/07\/rector-process-dry-run.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full \" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/07\/rector-process-dry-run.gif\" alt width=\"740\" height=\"480\"><\/a><figcaption class=\"wp-caption-text\">Uscita &#8220;diff&#8221; da Rector<\/figcaption><\/figure>\n<h2>A Quale Versione di PHP Eseguire il Transpiling<\/h2>\n<p>Per effettuare il transpiling del codice alle varie versioni di PHP, devono essere create le regole corrispondenti.<\/p>\n<p>Oggi, la libreria Rector include la maggior parte delle regole per trasportare il codice all&#8217;interno della gamma che va da PHP 8.0 a 7.1. Quindi possiamo effettuare il transpiling del nostro codice PHP in modo affidabile fino alla versione 7.1.<\/p>\n<p>Ci sono anche <a href=\"https:\/\/github.com\/rectorphp\/rector\/blob\/main\/docs\/rector_rules_overview.md#downgradephp71\" target=\"_blank\" rel=\"noopener noreferrer\">regole per la compilazione da PHP 7.1 a 7.0<\/a> e <a href=\"https:\/\/github.com\/rectorphp\/rector\/blob\/main\/docs\/rector_rules_overview.md#downgradephp70\" target=\"_blank\" rel=\"noopener noreferrer\">da 7.0 a 5.6<\/a>, ma queste non sono esaustive. Si sta lavorando per completarle, cos\u00ec alla fine potremo effettuare il transpiling del codice PHP fino alla versione 5.6.<\/p>\n<h2>Transpiling e Backporting<\/h2>\n<p>Il backporting \u00e8 simile al transpiling, ma pi\u00f9 semplice. Il codice di backporting non si basa necessariamente su nuove funzionalit\u00e0 di un linguaggio, perch\u00e9 la stessa funzionalit\u00e0 pu\u00f2 essere fornita ad una vecchia versione del linguaggio semplicemente copiando\/incollando\/adattando il codice corrispondente dalla nuova versione del linguaggio.<\/p>\n<p>Ad esempio, la funzione <code>str_contains<\/code> \u00e8 stata introdotta in PHP 8.0. La stessa funzione per PHP 7.4 e successivi pu\u00f2 essere facilmente implementata in questo modo:<\/p>\n<pre><code class=\"language-php\">if (!defined('PHP_VERSION_ID') || (defined('PHP_VERSION_ID') && PHP_VERSION_ID &lt; 80000)) {\n  if (!function_exists('str_contains')) {\n    \/**\n     * Checks if a string contains another\n     *\n     * @param string $haystack The string to search in\n     * @param string $needle The string to search\n     * @return boolean Returns TRUE if the needle was found in haystack, FALSE otherwise.\n     *\/\n    function str_contains(string $haystack, string $needle): bool\n    {\n      return strpos($haystack, $needle) !== false;\n    }\n  }\n}<\/code><\/pre>\n<p>Dato che il backporting \u00e8 pi\u00f9 semplice del transpiling, dovremmo optare per questa soluzione ogni volta che il backporting pu\u00f2 fare il lavoro.<\/p>\n<p>Per quanto riguarda il range tra PHP 8.0 e 7.1, possiamo utilizzare le librerie polyfill di <a href=\"https:\/\/symfony.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Symfony<\/a>:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/symfony\/polyfill-php71\/\" target=\"_blank\" rel=\"noopener noreferrer\">Polyfill PHP 7.1<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/symfony\/polyfill-php72\/\" target=\"_blank\" rel=\"noopener noreferrer\">Polyfill PHP 7.2<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/symfony\/polyfill-php73\/\" target=\"_blank\" rel=\"noopener noreferrer\">Polyfill PHP 7.3<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/symfony\/polyfill-php74\/\" target=\"_blank\" rel=\"noopener noreferrer\">Polyfill PHP 7.4<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/symfony\/polyfill-php80\/\" target=\"_blank\" rel=\"noopener noreferrer\">Polyfill PHP 8.0<\/a><\/li>\n<\/ul>\n<p>Queste librerie eseguono il backport delle seguenti funzioni, classi, costanti e interfacce:<\/p>\n<table style=\"height: 1173px\" width=\"335\">\n<thead>\n<tr>\n<th>Versione PHP<\/th>\n<th>Funzionalit\u00e0<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>7.2<\/td>\n<td>Funzioni:<\/p>\n<ul>\n<li><a href=\"https:\/\/php.net\/spl_object_id\" target=\"_blank\" rel=\"noopener noreferrer\"><code>spl_object_id<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/utf8_encode\" target=\"_blank\" rel=\"noopener noreferrer\"><code>utf8_encode<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/utf8_decode\" target=\"_blank\" rel=\"noopener noreferrer\"><code>utf8_decode<\/code><\/a><\/li>\n<\/ul>\n<p>Costanti:<\/p>\n<ul>\n<li><a href=\"https:\/\/php.net\/reserved.constants#constant.php-float-dig\" target=\"_blank\" rel=\"noopener noreferrer\"><code>PHP_FLOAT_*<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/reserved.constants#constant.php-os-family\" target=\"_blank\" rel=\"noopener noreferrer\"><code>PHP_OS_FAMILY<\/code><\/a><\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<tr>\n<td>7.3<\/td>\n<td>Funzioni:<\/p>\n<ul>\n<li><a href=\"https:\/\/php.net\/array_key_first\" target=\"_blank\" rel=\"noopener noreferrer\"><code>array_key_first<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/array_key_last\" target=\"_blank\" rel=\"noopener noreferrer\"><code>array_key_last<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/function.hrtime\" target=\"_blank\" rel=\"noopener noreferrer\"><code>hrtime<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/is_countable\" target=\"_blank\" rel=\"noopener noreferrer\"><code>is_countable<\/code><\/a><\/li>\n<\/ul>\n<p>Eccezioni:<\/p>\n<ul>\n<li><a href=\"https:\/\/php.net\/JsonException\" target=\"_blank\" rel=\"noopener noreferrer\"><code>JsonException<\/code><\/a><\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<tr>\n<td>7.4<\/td>\n<td>Funzioni:<\/p>\n<ul>\n<li><a href=\"https:\/\/php.net\/get_mangled_object_vars\" target=\"_blank\" rel=\"noopener noreferrer\"><code>get_mangled_object_vars<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/mb_str_split\" target=\"_blank\" rel=\"noopener noreferrer\"><code>mb_str_split<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/password_algos\" target=\"_blank\" rel=\"noopener noreferrer\"><code>password_algos<\/code><\/a><\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<tr>\n<td>8.0<\/td>\n<td>Interfacce:<\/p>\n<ul>\n<li><code>Stringable<\/code><\/li>\n<\/ul>\n<p>Classi:<\/p>\n<ul>\n<li><code>ValueError<\/code><\/li>\n<li><code>UnhandledMatchError<\/code><\/li>\n<\/ul>\n<p>Costanti:<\/p>\n<ul>\n<li><code>FILTER_VALIDATE_BOOL<\/code><\/li>\n<\/ul>\n<p>Funzioni:<\/p>\n<ul>\n<li><a href=\"https:\/\/php.net\/fdiv\" target=\"_blank\" rel=\"noopener noreferrer\"><code>fdiv<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/get_debug_type\" target=\"_blank\" rel=\"noopener noreferrer\"><code>get_debug_type<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/preg_last_error_msg\" target=\"_blank\" rel=\"noopener noreferrer\"><code>preg_last_error_msg<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/str_contains\" target=\"_blank\" rel=\"noopener noreferrer\"><code>str_contains<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/str_starts_with\" target=\"_blank\" rel=\"noopener noreferrer\"><code>str_starts_with<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/str_ends_with\" target=\"_blank\" rel=\"noopener noreferrer\"><code>str_ends_with<\/code><\/a><\/li>\n<li><a href=\"https:\/\/php.net\/get_resource_id\" target=\"_blank\" rel=\"noopener noreferrer\"><code>get_resource_id<\/code><\/a><\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Esempi di Transpiling di PHP<\/h2>\n<p>Esaminiamo alcuni esempi di transpiling del codice PHP e alcuni pacchetti su cui \u00e8 stato eseguito il transpiling.<\/p>\n<h3>Codice PHP<\/h3>\n<p>L&#8217;espressione <code>match<\/code> \u00e8 stata <a href=\"https:\/\/kinsta.com\/it\/blog\/php-8\/#match-expression\">introdotta in PHP 8.0<\/a>. Questo codice sorgente:<\/p>\n<pre><code class=\"language-php\">function getFieldValue(string $fieldName): ?string\n{\n  return match($fieldName) {\n    'foo' =&gt; 'foofoo',\n    'bar' =&gt; 'barbar',\n    'baz' =&gt; 'bazbaz',\n    default =&gt; null,\n  };\n}\n<\/code><\/pre>\n<p>&#8230;sar\u00e0 tradotto nella sua versione equivalente in PHP 7.4, utilizzando l&#8217;operatore <code>switch<\/code>:<\/p>\n<pre><code class=\"language-php\">function getFieldValue(string $fieldName): ?string\n{\n  switch ($fieldName) {\n    caso 'pippo':\n      ritorna 'foofoo';\n    caso 'bar':\n      ritorna 'barbar';\n    caso 'baz':\n      restituisce 'bazbaz';\n    predefinito:\n      restituisce 'null';\n  }\n}\n<\/code><\/pre>\n<p>Anche l&#8217;<a href=\"https:\/\/kinsta.com\/it\/blog\/php-8\/#nullsafe-operator\">operatore nullsafe<\/a> \u00e8 stato introdotto in PHP 8.0:<\/p>\n<pre><code class=\"language-php\">public function getValue(TypeResolverInterface $typeResolver): ?string\n{\n  return $this-&gt;getResolver($typeResolver)?-&gt;getValue();\n}\n<\/code><\/pre>\n<p>Il codice tradotto ha bisogno di assegnare prima il valore dell&#8217;operazione ad una nuova variabile, per evitare di eseguire l&#8217;operazione due volte:<\/p>\n<pre><code class=\"language-php\">public function getValue(TypeResolverInterface $typeResolver): ?string\n{\n  return ($val = $this-&gt;getResolver($typeResolver)) ? $val-&gt;getValue() : null;\n}\n<\/code><\/pre>\n<p>La <a href=\"https:\/\/kinsta.com\/it\/blog\/php-8\/#constructor-property-promotion\">promozione delle propriet\u00e0 del costruttore<\/a>, anche questa introdotta in PHP 8.0, permette agli sviluppatori di scrivere meno codice:<\/p>\n<pre><code class=\"language-php\">classe QueryResolver\n{\n  function __construct(protected QueryFormatter $queryFormatter)\n  {\n  }\n}\n<\/code><\/pre>\n<p>Quando si effettua il transpiling a PHP 7.4, viene prodotto il codice completo:<\/p>\n<pre><code class=\"language-php\"> classe QueryResolver\n {\n  protected QueryFormatter $queryFormatter;\n\n  funzione __construct(QueryFormatter $queryFormatter)\n  {\n    $this-&gt;queryFormatter = $queryFormatter;\n  }\n}\n<\/code><\/pre>\n<p>Il codice tradotto qui sopra contiene <a href=\"https:\/\/kinsta.com\/it\/blog\/php-7-4\/#typed-properties\">propriet\u00e0 tipizzate<\/a>, introdotte in PHP 7.4. Traducendo quel codice a PHP 7.3, queste sono sostituite con i docblock:<\/p>\n<pre><code class=\"language-php\"> class QueryResolver\n {\n  \/**\n   * @var QueryFormatter\n   *\/\n  protected $queryFormatter;\n\n  function __construct(QueryFormatter $queryFormatter)\n  {\n    $this-&gt;queryFormatter = $queryFormatter;\n  }\n}<\/code><\/pre>\n<h3>Pacchetti PHP<\/h3>\n<p>Le seguenti librerie sono state tradotte per la produzione:<\/p>\n<table>\n<thead>\n<tr>\n<th>Libreria\/descrizione<\/th>\n<th>Codice\/note<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/getrector.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">Rector<\/a><br \/>\nStrumento di ricostruzione PHP che rende possibile il transpiling<\/td>\n<td>&#8211; <a href=\"https:\/\/github.com\/rectorphp\/rector-src\" target=\"_blank\" rel=\"noopener noreferrer\">Codice sorgente<\/a><br \/>\n&#8211; <a href=\"https:\/\/github.com\/rectorphp\/rector\" target=\"_blank\" rel=\"noopener noreferrer\">Codice tradotto<\/a><br \/>\n&#8211; <a href=\"https:\/\/getrector.org\/blog\/prefixed-rector-by-default\" target=\"_blank\" rel=\"noopener noreferrer\">Note<\/a><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/tomasvotruba.com\/blog\/2017\/05\/03\/combine-power-of-php-code-sniffer-and-php-cs-fixer-in-3-lines\/\" target=\"_blank\" rel=\"noopener noreferrer\">Easy Coding Standards<\/a><br \/>\nStrumento per far corrispondere il codice PHP ad un insieme di regole<\/td>\n<td>&#8211; <a href=\"https:\/\/github.com\/symplify\/symplify\/tree\/main\/packages\/easy-coding-standard\" target=\"_blank\" rel=\"noopener noreferrer\">Codice sorgente<\/a><br \/>\n&#8211; <a href=\"https:\/\/github.com\/symplify\/easy-coding-standard\" target=\"_blank\" rel=\"noopener noreferrer\">Codice tradotto<\/a><br \/>\n&#8211; <a href=\"https:\/\/tomasvotruba.com\/blog\/introducing-ecs-prefixed-and-downgraded-to-php-71\/\" target=\"_blank\" rel=\"noopener noreferrer\">Note<\/a><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/graphql-api.com\" target=\"_blank\" rel=\"noopener noreferrer\">API GraphQL per WordPress<\/a><br \/>\nPlugin che fornisce un server GraphQL per WordPress<\/td>\n<td>&#8211; <a href=\"https:\/\/github.com\/leoloso\/PoP\/tree\/master\/layers\/GraphQLAPIForWP\/plugins\/graphql-api-for-wp\" target=\"_blank\" rel=\"noopener noreferrer\">Codice sorgente<\/a><br \/>\n&#8211; <a href=\"https:\/\/github.com\/GraphQLAPI\/graphql-api-for-wp-dist\/\" target=\"_blank\" rel=\"noopener noreferrer\">Codice tradotto<\/a><br \/>\n&#8211; <a href=\"https:\/\/graphql-api.com\/blog\/the-plugin-is-now-transpiled-from-php-80-to-71\/\" target=\"_blank\" rel=\"noopener noreferrer\">Note<\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Pro e Contro del Transpiling di PHP<\/h2>\n<p>Il vantaggio del transpiling di PHP \u00e8 gi\u00e0 stato descritto: permette al codice sorgente di utilizzare PHP 8.0 (cio\u00e8 l&#8217;ultima versione di PHP), che sar\u00e0 trasformato in una versione inferiore di PHP per la produzione, da eseguire in un&#8217;applicazione o ambiente legacy.<\/p>\n<p>Questo ci permette effettivamente di diventare sviluppatori migliori, producendo codice di qualit\u00e0 superiore, perch\u00e9 il nostro codice sorgente pu\u00f2 utilizzare i tipi unione di PHP 8.0, le propriet\u00e0 tipizzate di PHP 7.4 e i diversi tipi e pseudo-tipi aggiunti ad ogni nuova versione di PHP (<code>mixed<\/code> da PHP 8.0, <code>object<\/code> da PHP 7.2), tra le altre caratteristiche moderne di PHP.<\/p>\n<p>Usando queste funzionalit\u00e0, possiamo catturare meglio i bug durante lo sviluppo e scrivere codice pi\u00f9 leggibile.<\/p>\n<p>Ora diamo un&#8217;occhiata agli svantaggi.<\/p>\n<h3>Deve Essere Codificato e Mantenuto<\/h3>\n<p>Rector pu\u00f2 eseguire il transpiling del codice automaticamente, ma il processo richieder\u00e0 probabilmente qualche input manuale per adattarlo alla nostra configurazione specifica.<\/p>\n<h3>Anche le Librerie di Terze Parti Devono Essere Tradotte<\/h3>\n<p>Questo diventa un problema ogni volta che il loro traspiling produce degli errori, perch\u00e9 dobbiamo poi scavare nel codice sorgente per scoprirne le cause. Se il problema pu\u00f2 essere risolto e il progetto \u00e8 open source, dovremo inviare una richiesta di pull. Se la libreria non \u00e8 open source, potremmo imbatterci in un blocco stradale.<\/p>\n<h3>Rector Non Ci Dice Quando Non Si Pu\u00f2 Eseguire il Transpiling del Codice<\/h3>\n<p>Se il codice sorgente contiene attributi di PHP 8.0 o qualsiasi altra funzionalit\u00e0 che non pu\u00f2 essere oggetto di transpiling, non possiamo procedere. Tuttavia, Rector non controlla questa condizione, quindi dobbiamo farlo manualmente. Potrebbe non essere un grosso problema per quanto riguarda il nostro codice sorgente, perch\u00e9 abbiamo gi\u00e0 familiarit\u00e0 con questo, ma potrebbe diventare un ostacolo per le dipendenze di terzi.<\/p>\n<h3>Le Informazioni di Debugging Utilizzano il Codice Tradotto, Non il Codice Sorgente<\/h3>\n<p>Quando l&#8217;applicazione produce un messaggio di errore con uno stack trace in produzione, il numero di linea punter\u00e0 al codice tradotto. Per trovare il numero di linea corrispondente nel codice sorgente, abbiamo bisogno di riconvertire dal codice tradotto al codice originale.<\/p>\n<h3>Il Codice Tradotto Deve Avere Anche il Prefisso<\/h3>\n<p>Il nostro progetto tradotto e qualche altra libreria installata nell&#8217;ambiente di produzione potrebbero utilizzare la stessa dipendenza di terze parti. Questa dipendenza di terze parti sar\u00e0 tradotta per il nostro progetto e manterr\u00e0 il suo codice sorgente originale per l&#8217;altra libreria. Quindi alla versione tradotta deve essere aggiunto un prefisso tramite <a href=\"https:\/\/github.com\/humbug\/php-scoper\" target=\"_blank\" rel=\"noopener noreferrer\">PHP-Scoper<\/a>, <a href=\"https:\/\/github.com\/BrianHenryIE\/strauss\" target=\"_blank\" rel=\"noopener noreferrer\">Strauss<\/a> o qualche altro strumento per evitare possibili conflitti.<\/p>\n<h3>Il Transpiling Deve Avvenire Durante l&#8217;Integrazione Continua (CI)<\/h3>\n<p>Dato che il codice tradotto sovrascriver\u00e0 naturalmente il codice sorgente, non dovremmo eseguire il transpiling sui nostri computer di sviluppo, o rischieremo di creare effetti collaterali. Eseguire il processo durante un&#8217;esecuzione di CI \u00e8 pi\u00f9 corretto (maggiori informazioni in seguito).<\/p>\n<h2>Come Eseguire il Transpiling di PHP<\/h2>\n<p>Per prima cosa dobbiamo installare Rector nel nostro progetto di sviluppo:<\/p>\n<pre><code class=\"language-bash\">composer require rector\/rector --dev\n<\/code><\/pre>\n<p>Poi creiamo un file di configurazione <code>rector.php<\/code> nella directory principale del progetto contenente l&#8217;insieme di regole necessarie. Per effettuare il downgrade del codice da PHP 8.0 a 7.1, utilizziamo questa configurazione:<\/p>\n<pre><code class=\"language-php\">use Rector\\SetValueObject\\DowngradeSetList;\nusa Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator;\n\nreturn static function (ContainerConfigurator $containerConfigurator): void {\n    $containerConfigurator-&gt;import(DowngradeSetList::PHP_80);\n    $containerConfigurator-&gt;import(DowngradeSetList::PHP_74);\n    $containerConfigurator-&gt;import(DowngradeSetList::PHP_73);\n    $containerConfigurator-&gt;import(DowngradeSetList::PHP_72);\n};\n<\/code><\/pre>\n<p>Per assicurarci che il processo venga eseguito come previsto, possiamo eseguire il comando <code>process<\/code> di Rector in modalit\u00e0 dry, passando la posizione o le posizioni da processare (in questo caso, tutti i file nella cartella <code>src\/<\/code>):<\/p>\n<pre><code class=\"language-bash\">vendor\/bin\/rector process src --dry-run\n<\/code><\/pre>\n<p>Per eseguire il transpiling, eseguiamo il comando <code>process<\/code> di Rector, che modificher\u00e0 i file nella loro posizione esistente:<\/p>\n<pre><code class=\"language-bash\">vendor\/bin\/rector process src\n<\/code><\/pre>\n<p>Nota bene: se eseguiamo <code>rector process<\/code> nei nostri computer di sviluppo, il codice sorgente sar\u00e0 convertito sul posto, sotto <code>src\/<\/code>. Tuttavia, vogliamo produrre il codice convertito in una posizione diversa per non sovrascrivere il codice sorgente durante il downgrade. Per questo motivo, l&#8217;esecuzione del processo \u00e8 pi\u00f9 corretto durante l&#8217;integrazione continua.<\/p>\n<h2>Ottimizzare il Processo di Transpiling<\/h2>\n<p>Per generare un deliverable tradotto per la produzione, deve essere convertito solo il codice per la produzione; il codice necessario solo per lo sviluppo pu\u00f2 essere saltato. Questo significa che possiamo evitare di eseguire il transpiling di tutti i test (sia per il nostro progetto che per le sue dipendenze) e tutte le dipendenze per lo sviluppo.<\/p>\n<p>Per quanto riguarda i test, sapremo gi\u00e0 dove si trovano quelli per il nostro progetto &#8211; per esempio, nella cartella <code>tests\/<\/code>. Dobbiamo anche scoprire dove sono quelli per le dipendenze &#8211; per esempio, nelle sottocartelle <code>tests\/<\/code>, <code>test\/<\/code> e <code>Test\/<\/code> (per le diverse librerie). Poi diciamo a Rector di saltare l&#8217;elaborazione di queste cartelle:<\/p>\n<pre><code class=\"language-php\">return static function (ContainerConfigurator $containerConfigurator): void {\n  \/\/ ...\n\n  $parameters-&gt;set(Option::SKIP, [\n    \/\/ Skip tests\n    '*\/tests\/*',\n    '*\/test\/*',\n    '*\/Test\/*',\n  ]);\n};<\/code><\/pre>\n<p>Per quanto riguarda le dipendenze, Composer sa quali sono per lo sviluppo (quelle sotto la voce <code>require-dev<\/code> in <code>composer.json<\/code>) e quali sono per la produzione (quelle sotto la voce <code>require<\/code>).<\/p>\n<p>Per recuperare da Composer i percorsi di tutte le dipendenze per la produzione, eseguiamo:<\/p>\n<pre><code class=\"language-bash\">composer info --path --no-dev\n<\/code><\/pre>\n<p>Questo comando produrr\u00e0 un elenco di dipendenze con nome e percorso, come questo:<\/p>\n<pre><code>brain\/cortex                     \/Users\/leo\/GitHub\/leoloso\/PoP\/vendor\/brain\/cortex\ncomposer\/installers              \/Users\/leo\/GitHub\/leoloso\/PoP\/vendor\/composer\/installers\ncomposer\/semver                  \/Users\/leo\/GitHub\/leoloso\/PoP\/vendor\/composer\/semver\nguzzlehttp\/guzzle                \/Users\/leo\/GitHub\/leoloso\/PoP\/vendor\/guzzlehttp\/guzzle\nleague\/pipeline                  \/Users\/leo\/GitHub\/leoloso\/PoP\/vendor\/league\/pipeline\n<\/code><\/pre>\n<p>Possiamo estrarre tutti i percorsi e inserirli nel comando Rector, che elaborer\u00e0 la cartella <code>src\/<\/code> del nostro progetto pi\u00f9 le cartelle contenenti tutte le dipendenze per la produzione:<\/p>\n<pre><code class=\"language-bash\">$ paths=\"$(composer info --path --no-dev | cut -d' ' -f2- | sed 's\/ \/\/g' | tr '\\n' ' ')\"\n$ vendor\/bin\/rector process src $paths<\/code><\/pre>\n<p>Un ulteriore miglioramento pu\u00f2 impedire a Rector di elaborare quelle dipendenze che gi\u00e0 utilizzano la versione PHP di destinazione. Se una libreria \u00e8 stata codificata con PHP 7.1 (o qualsiasi versione inferiore), allora non c&#8217;\u00e8 bisogno di effettuare il transpiling a PHP 7.1.<\/p>\n<p>Per questo, possiamo ottenere l&#8217;elenco delle librerie che richiedono PHP 7.2 e superiori ed elaborare solo quelle. Otterremo i nomi di tutte queste librerie tramite il comando <code>why-not<\/code> di Composer, in questo modo:<\/p>\n<pre><code class=\"language-bash\">composer why-not php \"7.1.*\" | grep -o \"\\S*\\\/\\S*\"<\/code><\/pre>\n<p>Dato che questo comando non funziona con il flag <code>--no-dev<\/code>, per includere solo le dipendenze per la produzione dobbiamo prima rimuovere le dipendenze per lo sviluppo e rigenerare l&#8217;autoloader, eseguire il comando e poi aggiungerle nuovamente:<\/p>\n<pre><code class=\"language-bash\">$ composer install --no-dev\n$ packages=$(composer why-not php \"7.1.*\" | grep -o \"\\S*\\\/\\S*\")\n$ composer install<\/code><\/pre>\n<p>Il comando <code>info --path<\/code> di Composer recupera il percorso di un pacchetto, con questo formato:<\/p>\n<pre><code class=\"language-bash\"># Executing this command\n$ composer info psr\/cache --path   \n# Produces this response:\npsr\/cache \/Users\/leo\/GitHub\/leoloso\/PoP\/vendor\/psr\/cache\n<\/code><\/pre>\n<p>Eseguiamo questo comando per tutti gli elementi della nostra lista per ottenere tutti i percorsi da convertire:<\/p>\n<pre><code class=\"language-bash\">for package in $packages\ndo\n  path=$(composer info $package --path | cut -d' ' -f2-)\n  paths=\"$paths $path\"\ndone<\/code><\/pre>\n<p>Infine, forniamo questa lista a Rector (pi\u00f9 la cartella <code>src\/<\/code> del progetto):<\/p>\n<pre><code class=\"language-bash\">vendor\/bin\/rector process src $paths<\/code><\/pre>\n<h2>Trappole da Evitare Quando si Esegue il Transpiling del Codice<\/h2>\n<p>Il Transpiling del codice potrebbe essere considerato un&#8217;arte che spesso richiede modifiche specifiche al progetto. Vediamo alcuni problemi che potremmo riscontrare.<\/p>\n<h3>Le Regole Concatenate non Sono Sempre Elaborate<\/h3>\n<p>Una regola concatenata \u00e8 una regola che ha bisogno di convertire il codice prodotto da una regola precedente.<\/p>\n<p>Ad esempio, la libreria <code>symfony\/cache<\/code> contiene <a href=\"https:\/\/github.com\/symfony\/cache\/blob\/be5707f\/CacheItem.php#L115\" target=\"_blank\" rel=\"noopener noreferrer\">questo codice<\/a>:<\/p>\n<pre><code class=\"language-php\">final class CacheItem implements ItemInterface\n{\n  public function tag($tags): ItemInterface\n  {\n    \/\/ ...\n    return $this;\n  }\n}<\/code><\/pre>\n<p>Quando si esegue il transpiling da PHP 7.4 a 7.3, la funzione <code>tag<\/code> deve subire due modifiche:<\/p>\n<ul>\n<li>Il tipo di ritorno <code>ItemInterface<\/code> deve essere prima convertito in <code>self<\/code>, a causa della regola <a href=\"https:\/\/github.com\/rectorphp\/rector-src\/blob\/f451b0b\/rules\/DowngradePhp74\/Rector\/ClassMethod\/DowngradeCovariantReturnTypeRector.php\"><code>DowngradeCovariantReturnTypeRector<\/code><\/a><\/li>\n<li>Il tipo di ritorno <code>self<\/code> deve poi essere rimosso, a causa della regola <a href=\"https:\/\/github.com\/rectorphp\/rector-src\/blob\/f451b0b\/rules\/DowngradePhp74\/Rector\/ClassMethod\/DowngradeSelfTypeDeclarationRector.php\"><code>DowngradeSelfTypeDeclarationRector<\/code><\/a><\/li>\n<\/ul>\n<p>Il risultato finale dovrebbe essere questo:<\/p>\n<pre><code class=\"language-php\">final class CacheItem implements ItemInterface\n{\n  public function tag($tags)\n  {\n    \/\/ ...\n    return $this;\n  }\n}\n<\/code><\/pre>\n<p>Tuttavia, Rector emette solo la fase intermedia:<\/p>\n<pre><code class=\"language-php\">final class CacheItem implements ItemInterface\n{\n  public function tag($tags): self\n  {\n    \/\/ ...\n    return $this;\n  }\n}<\/code><\/pre>\n<p>Il problema \u00e8 che <a href=\"https:\/\/github.com\/rectorphp\/rector\/issues\/5962\" target=\"_blank\" rel=\"noopener noreferrer\">Rector non pu\u00f2 sempre controllare l&#8217;ordine in cui vengono applicate le regole<\/a>.<\/p>\n<p>La soluzione \u00e8 quella di identificare le regole concatenate che rimangono non elaborate ed eseguire di nuovo Rector per applicarle.<\/p>\n<p>Per identificare le regole concatenate, eseguiamo Rector due volte sul codice sorgente, in questo modo:<\/p>\n<pre><code class=\"language-bash\">$ vendor\/bin\/rector process src\n$ vendor\/bin\/rector process src --dry-run\n<\/code><\/pre>\n<p>La prima volta, eseguiamo Rector come previsto, per eseguire il transpiling. La seconda volta, usiamo il flag <code>--dry-run<\/code> per scoprire se ci sono ancora modifiche da fare. Se ci sono, il comando uscir\u00e0 con un codice di errore e l&#8217;output &#8220;diff&#8221; indicher\u00e0 le regole che possono ancora essere applicate. Questo significherebbe che la prima esecuzione non \u00e8 stata completata, e alcune regole concatenate non sono state elaborate.<\/p>\n<figure style=\"width: 901px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/07\/rector-process-run-dry.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full \" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/07\/rector-process-run-dry.png\" alt=\"Esecuzione di Rector con il flag --dry-run\" width=\"901\" height=\"903\"><\/a><figcaption class=\"wp-caption-text\">Esecuzione di Rector con il flag &#8211;dry-run<\/figcaption><\/figure>\n<p>Una volta che abbiamo identificato la regola (o le regole) non applicate, possiamo creare un altro file di configurazione di Rector &#8211; per esempio, <code>rector-chained-rule.php<\/code> eseguir\u00e0 la regola mancante. Invece di elaborare una serie completa di regole per tutti i file sotto <code>src\/<\/code>, questa volta possiamo eseguire la regola mancante sul file specifico dove deve essere applicata:<\/p>\n<pre><code class=\"language-php\">\/\/ rector-chained-rule.php\nuse Rector\\Core\\Configuration\\Option;\nuse Rector\\DowngradePhp74\\Rector\\ClassMethod\\DowngradeSelfTypeDeclarationRector;\nuse Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator;\n\nreturn static function (ContainerConfigurator $containerConfigurator): void {\n  $services = $containerConfigurator-&gt;services();\n  $services-&gt;set(DowngradeSelfTypeDeclarationRector::class);\n\n  $parameters = $containerConfigurator-&gt;parameters();\n  $parameters-&gt;set(Option::PATHS, [\n    __DIR__ . '\/vendor\/symfony\/cache\/CacheItem.php',\n  ]);\n};\n<\/code><\/pre>\n<p>Infine, diciamo a Rector di utilizzare nel suo secondo passaggio il nuovo file di configurazione tramite l&#8217;input <code>--config<\/code>:<\/p>\n<pre><code class=\"language-bash\"># First pass with all modifications\n$ vendor\/bin\/rector process src\n\n# Second pass to fix a specific problem\n$ vendor\/bin\/rector process --config=rector-chained-rule.php<\/code><\/pre>\n<h3>Le Dipendenze di Composer Possono Essere Incoerenti<\/h3>\n<p>Le librerie potrebbero dichiarare che una dipendenza \u00e8 destinata allo sviluppo (cio\u00e8 sotto <code>require-dev<\/code> in <code>composer.json<\/code>), ma comunque fare riferimento a codice proveniente da queste per la produzione (ad esempio su alcuni file in <code>src\/<\/code>, non <code>tests\/<\/code>).<\/p>\n<p>Di solito, questo non \u00e8 un problema perch\u00e9 quel codice potrebbe non essere caricato in produzione, quindi non ci sar\u00e0 mai un errore nell&#8217;applicazione. Tuttavia, quando Rector elabora il codice sorgente e le sue dipendenze, conferma che tutto il codice referenziato pu\u00f2 essere caricato. Rector dar\u00e0 un errore se un qualunque file fa riferimento a qualche blocco di codice di una libreria non installata (perch\u00e9 \u00e8 stato dichiarato necessario solo per lo sviluppo).<\/p>\n<p>Per esempio, la classe <a href=\"https:\/\/github.com\/symfony\/symfony\/blob\/8f03a1f\/src\/Symfony\/Component\/Cache\/Messenger\/EarlyExpirationHandler.php\"><code>EarlyExpirationHandler<\/code><\/a> del componente Cache di Symfony implementa l&#8217;interfaccia <a href=\"https:\/\/github.com\/symfony\/symfony\/blob\/191cb52\/src\/Symfony\/Component\/Messenger\/Handler\/MessageHandlerInterface.php\"><code>MessageHandlerInterface<\/code><\/a> del componente Messenger:<\/p>\n<pre><code class=\"language-php\">class EarlyExpirationHandler implements MessageHandlerInterface\n{\n    \/\/...\n}<\/code><\/pre>\n<p>Tuttavia, <code>symfony\/cache<\/code> dichiara <code>symfony\/messenger<\/code> come <a href=\"https:\/\/github.com\/symfony\/symfony\/blob\/6fe82d8\/src\/Symfony\/Component\/Cache\/composer.json#L43\" target=\"_blank\" rel=\"noopener noreferrer\">dipendenza per lo sviluppo<\/a>. Quindi, quando si esegue Rector su un progetto che dipende da <code>symfony\/cache<\/code>, verr\u00e0 emesso un errore:<\/p>\n<pre><code>[ERROR] Could not process \"vendor\/symfony\/cache\/Messenger\/EarlyExpirationHandler.php\" file, due to:             \n  \"Analyze error: \"Class Symfony\\Component\\Messenger\\Handler\\MessageHandlerInterface not found.\". Include your files in \"$parameters-&gt;set(Option::AUTOLOAD_PATHS, [...]);\" in \"rector.php\" config.\n  See https:\/\/github.com\/rectorphp\/rector#configuration\".   <\/code><\/pre>\n<p>Ci sono tre soluzioni a questo problema:<\/p>\n<ol>\n<li>Nella configurazione di Rector, saltare l&#8217;elaborazione del file che fa riferimento a quel blocco di codice:<\/li>\n<\/ol>\n<pre><code class=\"language-php\">return static function (ContainerConfigurator $containerConfigurator): void {\n  \/\/ ...\n\n  $parameters-&gt;set(Option::SKIP, [\n    __DIR__ . '\/vendor\/symfony\/cache\/Messenger\/EarlyExpirationHandler.php',\n  ]);\n};\n<\/code><\/pre>\n<ol start=\"2\">\n<li>Scaricare la libreria mancante e aggiungere il suo percorso in modo che venga caricata automaticamente da Rector:<\/li>\n<\/ol>\n<pre><code class=\"language-php\">return static function (ContainerConfigurator $containerConfigurator): void {\n  \/\/ ...\n\n  $parameters-&gt;set(Option::AUTOLOAD_PATHS, [\n    __DIR__ . '\/vendor\/symfony\/messenger',\n  ]);\n};\n<\/code><\/pre>\n<ol start=\"3\">\n<li>Fare in modo che il progetto dipenda dalla libreria mancante per la produzione:<\/li>\n<\/ol>\n<pre><code class=\"language-bash\">composer require symfony\/messenger\n<\/code><\/pre>\n<h2>Traspiling e Integrazione Continua<\/h2>\n<p>Come accennato in precedenza, quando eseguiamo Rector nei nostri computer di sviluppo dobbiamo utilizzare il flag <code>--dry-run<\/code>, altrimenti il codice sorgente verr\u00e0 sovrascritto con il codice tradotto. Per questo motivo, \u00e8 meglio eseguire l&#8217;effettivo transpiling durante l&#8217;integrazione continua (CI), durante la quale per eseguire il processo possiamo far girare dei runner temporanei.<\/p>\n<p>Un momento ideale per eseguire il processo di transpiling \u00e8 quando si genera la release del progetto. Ad esempio, il <a href=\"https:\/\/github.com\/GraphQLAPI\/graphql-api-for-wp\/blob\/3f9fd52ddf318b9fbb33653de8acfec8dc4b4665\/.github\/workflows\/main.yml\" target=\"_blank\" rel=\"noopener noreferrer\">codice qui sotto<\/a> \u00e8 un workflow per <a href=\"https:\/\/github.com\/features\/actions\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub Actions<\/a>, che crea la release di un plugin WordPress:<\/p>\n<pre><code class=\"language-yml\">name: Generate Installable Plugin and Upload as Release Asset\non:\n  release:\n    types: [published]\njobs:\n  build:\n    name: Build, Downgrade and Upload Release\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions\/checkout@v2\n      - name: Downgrade code for production (to PHP 7.1)\n        run: |\n          composer install\n          vendor\/bin\/rector process\n          sed -i 's\/Requires PHP: 7.4\/Requires PHP: 7.1\/' graphql-api.php\n      - name: Build project for production\n        run: |\n          composer install --no-dev --optimize-autoloader\n          mkdir build\n      - name: Create artifact\n        uses: montudor\/action-zip@v0.1.0\n        with:\n          args: zip -X -r build\/graphql-api.zip . -x *.git* node_modules\/\\* .* \"*\/\\.*\" CODE_OF_CONDUCT.md CONTRIBUTING.md ISSUE_TEMPLATE.md PULL_REQUEST_TEMPLATE.md rector.php *.dist composer.* dev-helpers** build**\n      - name: Upload artifact\n        uses: actions\/upload-artifact@v2\n        with:\n            name: graphql-api\n            path: build\/graphql-api.zip\n      - name: Upload to release\n        uses: JasonEtco\/upload-to-release@master\n        with:\n          args: build\/graphql-api.zip application\/zip\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}<\/code><\/pre>\n<p>Questo flusso di lavoro contiene una procedura standard per la <a href=\"https:\/\/leoloso.com\/posts\/github-action-to-release-wp-plugin\/\" target=\"_blank\" rel=\"noopener noreferrer\">release di un plugin WordPress tramite GitHub Actions<\/a>. La nuova aggiunta, per il transpiling del codice del plugin da PHP 7.4 a 7.1, avviene in questo passaggio:<\/p>\n<pre><code class=\"language-yml\">      - name: Downgrade code for production (to PHP 7.1)\n        run: |\n          vendor\/bin\/rector process\n          sed -i 's\/Requires PHP: 7.4\/Requires PHP: 7.1\/' graphql-api.php\n<\/code><\/pre>\n<p>Preso tutto insieme, questo workflow ora esegue i seguenti passaggi:<\/p>\n<ol>\n<li>Controlla il codice sorgente di un plugin WordPress scritto con PHP 7.4 dalla sua repository<\/li>\n<li>Installa le sue dipendenze Composer<\/li>\n<li>Esegue il transpiling del codice da PHP 7.4 a 7.1<\/li>\n<li>Modifica la voce &#8220;Requires PHP&#8221; nell&#8217;intestazione del file principale del plugin da <code>\"7.4\"<\/code> a <code>\"7.1\"<\/code><\/li>\n<li>Rimuove le dipendenze necessarie allo sviluppo<\/li>\n<li>Crea il file .zip del plugin, escludendo tutti i file non necessari<\/li>\n<li>Carica il file .zip come risorsa di release (e, in aggiunta, come artefatto alla GitHub Action)<\/li>\n<\/ol>\n<h2>Testare il Codice di Transpiling<\/h2>\n<p>Una volta eseguito il transpiling del codice a PHP 7.1, come facciamo a sapere che funziona correttamente? Oppure, in altre parole, come facciamo a sapere che \u00e8 stato convertito completamente e che non sono stati lasciati residui di versioni superiori del codice PHP?<\/p>\n<p>In modo simile al transpiling del codice, possiamo implementare la soluzione all&#8217;interno di un processo CI. L&#8217;idea \u00e8 quella di impostare l&#8217;ambiente del runner con PHP 7.1 ed eseguire un linter sul codice ottenuto dal transpiling. Se qualche frammento di codice non \u00e8 compatibile con PHP 7.1 (come una propriet\u00e0 tipizzata di PHP 7.4 che non \u00e8 stata convertita), allora il linter lancer\u00e0 un errore.<\/p>\n<p>Un linter PHP che funziona bene \u00e8 <a href=\"https:\/\/github.com\/php-parallel-lint\/PHP-Parallel-Lint\" target=\"_blank\" rel=\"noopener noreferrer\">PHP Parallel Lint<\/a>. Possiamo installare questa libreria come dipendenza per lo sviluppo nel nostro progetto, o fare in modo che il processo CI la installi come progetto Composer indipendente:<\/p>\n<pre><code class=\"language-bash\">composer create-project php-parallel-lint\/php-parallel-lint\n<\/code><\/pre>\n<p>Ogni volta che il codice contiene PHP 7.2 e superiore, PHP Parallel Lint lancia un errore come <a href=\"https:\/\/github.com\/leoloso\/PoP\/runs\/2751846434?check_suite_focus=true\" target=\"_blank\" rel=\"noopener noreferrer\">questo<\/a>:<\/p>\n<pre><code>Run php-parallel-lint\/parallel-lint layers\/ vendor\/ --exclude vendor\/symfony\/polyfill-ctype\/bootstrap80.php --exclude vendor\/symfony\/polyfill-intl-grapheme\/bootstrap80.php --exclude vendor\/symfony\/polyfill-intl-idn\/bootstrap80.php --exclude vendor\/symfony\/polyfill-intl-normalizer\/bootstrap80.php --exclude vendor\/symfony\/polyfill-mbstring\/bootstrap80.php\nPHP 7.1.33 | 10 parallel jobs\n............................................................   60\/2870 (2 %)\n............................................................  120\/2870 (4 %)\n...\n............................................................  660\/2870 (22 %)\n.............X..............................................  720\/2870 (25 %)\n............................................................  780\/2870 (27 %)\n...\n............................................................ 2820\/2870 (98 %)\n..................................................           2870\/2870 (100 %)<\/code><code>\n\n\nChecked 2870 files in 15.4 seconds\nSyntax error found in 1 file\n\n------------------------------------------------------------\nParse error: layers\/GraphQLAPIForWP\/plugins\/graphql-api-for-wp\/graphql-api.php:55\n    53|     '0.8.0',\n    54|     \\__('GraphQL API for WordPress', 'graphql-api'),\n  &gt; 55| ))) {\n    56|     $plugin-&gt;setup();\n    57| }\nUnexpected ')' in layers\/GraphQLAPIForWP\/plugins\/graphql-api-for-wp\/graphql-api.php on line 55\nError: Process completed with exit code 1.\n<\/code><\/pre>\n<p>Aggiungiamo il linter nel flusso di lavoro della nostra CI. I passaggi da eseguire per convertire il codice da PHP 8.0 a 7.1 e testarlo sono:<\/p>\n<ol>\n<li>Controllare il codice sorgente<\/li>\n<li>Far eseguire all&#8217;ambiente PHP 8.0, cos\u00ec Rector pu\u00f2 interpretare il codice sorgente<\/li>\n<li>Convertire il codice in PHP 7.1<\/li>\n<li>Installare lo strumento PHP linter<\/li>\n<li>Cambiare la versione PHP dell&#8217;ambiente a 7.1<\/li>\n<li>Eseguire il linter sul codice convertito<\/li>\n<\/ol>\n<p>Questo <a href=\"https:\/\/github.com\/leoloso\/PoP\/blob\/b93d3e35cb59e0281b45899fd82231c3d8cbbe25\/.github\/workflows\/downgrade_php_tests.yml\" target=\"_blank\" rel=\"noopener noreferrer\">workflow di GitHub Action<\/a> fa tutto il lavoro:<\/p>\n<pre><code class=\"language-yaml\">name: Downgrade PHP tests\njobs:\n  main:\n    name: Downgrade code to PHP 7.1 via Rector, and execute tests\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions\/checkout@v2\n\n      - name: Set-up PHP\n        uses: shivammathur\/setup-php@v2\n        with:\n          php-version: 8.0\n          coverage: none\n\n      - name: Local packages - Downgrade PHP code via Rector\n        run: |\n          composer install\n          vendor\/bin\/rector process\n\n      # Prepare for testing on PHP 7.1\n      - name: Install PHP Parallel Lint\n        run: composer create-project php-parallel-lint\/php-parallel-lint --ansi\n\n      - name: Switch to PHP 7.1\n        uses: shivammathur\/setup-php@v2\n        with:\n          php-version: 7.1\n          coverage: none\n\n      # Lint the transpiled code\n      - name: Run PHP Parallel Lint on PHP 7.1\n        run: php-parallel-lint\/parallel-lint src\/ vendor\/ --exclude vendor\/symfony\/polyfill-ctype\/bootstrap80.php --exclude vendor\/symfony\/polyfill-intl-grapheme\/bootstrap80.php --exclude vendor\/symfony\/polyfill-intl-idn\/bootstrap80.php --exclude vendor\/symfony\/polyfill-intl-normalizer\/bootstrap80.php --exclude vendor\/symfony\/polyfill-mbstring\/bootstrap80.php<\/code><\/pre>\n<p>Si noti che diversi file <code>bootstrap80.php<\/code> delle librerie polyfill di Symfony (che non hanno bisogno di essere convertiti) devono essere esclusi dal linter. Questi file contengono PHP 8.0, quindi il linter potrebbe dare degli errori quando li processa. Tuttavia, escludere questi file \u00e8 sicuro poich\u00e9 saranno caricati in produzione solo quando <a href=\"https:\/\/github.com\/symfony\/polyfill-mbstring\/blob\/9ad2f3c\/bootstrap.php#L14-L16\" target=\"_blank\" rel=\"noopener noreferrer\">si utilizza PHP 8.0 o superiore<\/a>:<\/p>\n<pre><code class=\"language-php\">se (\\PHP_VERSION_ID &gt;= 80000) {\n  return require __DIR__.'\/bootstrap80.php';\n}\n<\/code><\/pre>\n\n<h2>Riepilogo<\/h2>\n<p>In questo articolo abbiamo mostrato come eseguire il transpiling del nostro codice PHP al fine di utilizzare PHP 8.0 nel codice sorgente e creare una release che funziona anche su PHP 7.1. Il transpiling viene eseguito tramite <a href=\"https:\/\/github.com\/rectorphp\/rector\" target=\"_blank\" rel=\"noopener noreferrer\">Rector<\/a>, un reconstructor PHP.<\/p>\n<p>Eseguire il transpiling del codice ci permette di catturare meglio i bug nello sviluppo e produrre codice naturalmente pi\u00f9 facile da leggere e comprendere.<\/p>\n<p>Il transpiling ci permette anche di disabbinare il nostro codice da CMS con specifici requisiti PHP. Ora possiamo farlo se desideriamo utilizzare l&#8217;ultima versione di PHP per creare un plugin WordPress o un modulo Drupal e renderli disponibili al pubblico senza limitare gravemente la nostra base di utenti.<\/p>\n<p><em>Vi \u00e8 rimasta qualche domanda sul transpiling di PHP? Scrivetele nella sezione dei commenti!<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In circostanze ideali, dovremmo usare PHP 8.0 (l&#8217;ultima versione al momento in cui scriviamo questo articolo) per tutti i nostri siti e aggiornarlo non appena viene &#8230;<\/p>\n","protected":false},"author":196,"featured_media":47875,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kinsta_gated_content":false,"_kinsta_gated_content_redirect":"","footnotes":""},"tags":[41,13394],"topic":[26187,26189],"class_list":["post-47870","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-php","tag-programming","topic-funzione-php","topic-impara-php"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v24.6 (Yoast SEO v24.6) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Guida Definitiva al Transpiling del Codice PHP<\/title>\n<meta name=\"description\" content=\"Stanco di lavorare con pi\u00f9 versioni di PHP? Impara a scrivere codice sorgente con PHP 8.0 e convertirlo alle versioni precedenti di PHP.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/\" \/>\n<meta property=\"og:locale\" content=\"it_IT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Guida Definitiva al Transpiling del Codice PHP\" \/>\n<meta property=\"og:description\" content=\"Stanco di lavorare con pi\u00f9 versioni di PHP? Impara a scrivere codice sorgente con PHP 8.0 e convertirlo alle versioni precedenti di PHP.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/\" \/>\n<meta property=\"og:site_name\" content=\"Kinsta\u00ae\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/kinstaitalia\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-24T13:09:11+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-03-14T13:35:01+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1460\" \/>\n\t<meta property=\"og:image:height\" content=\"730\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Leonardo Losoviz\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:description\" content=\"Stanco di lavorare con pi\u00f9 versioni di PHP? Impara a scrivere codice sorgente con PHP 8.0 e convertirlo alle versioni precedenti di PHP.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg\" \/>\n<meta name=\"twitter:creator\" content=\"@losoviz\" \/>\n<meta name=\"twitter:site\" content=\"@Kinsta_IT\" \/>\n<meta name=\"twitter:label1\" content=\"Scritto da\" \/>\n\t<meta name=\"twitter:data1\" content=\"Leonardo Losoviz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tempo di lettura stimato\" \/>\n\t<meta name=\"twitter:data2\" content=\"22 minuti\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/\"},\"author\":{\"name\":\"Leonardo Losoviz\",\"@id\":\"https:\/\/kinsta.com\/it\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238\"},\"headline\":\"Guida Definitiva al Transpiling del Codice PHP\",\"datePublished\":\"2021-09-24T13:09:11+00:00\",\"dateModified\":\"2023-03-14T13:35:01+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/\"},\"wordCount\":3885,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/it\/#organization\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg\",\"keywords\":[\"php\",\"programming\"],\"articleSection\":[\"Sviluppo Web\"],\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/\",\"url\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/\",\"name\":\"Guida Definitiva al Transpiling del Codice PHP\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/it\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg\",\"datePublished\":\"2021-09-24T13:09:11+00:00\",\"dateModified\":\"2023-03-14T13:35:01+00:00\",\"description\":\"Stanco di lavorare con pi\u00f9 versioni di PHP? Impara a scrivere codice sorgente con PHP 8.0 e convertirlo alle versioni precedenti di PHP.\",\"breadcrumb\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#breadcrumb\"},\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#primaryimage\",\"url\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg\",\"contentUrl\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg\",\"width\":1460,\"height\":730,\"caption\":\"Guida Definitiva al Transpiling del Codice PHP\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kinsta.com\/it\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Impara PHP\",\"item\":\"https:\/\/kinsta.com\/it\/argomenti\/impara-php\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Guida Definitiva al Transpiling del Codice PHP\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kinsta.com\/it\/#website\",\"url\":\"https:\/\/kinsta.com\/it\/\",\"name\":\"Kinsta\u00ae\",\"description\":\"Soluzioni di hosting premium, veloci e sicure\",\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/it\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kinsta.com\/it\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"it-IT\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/kinsta.com\/it\/#organization\",\"name\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/it\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/kinsta.com\/it\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/12\/kinsta-logo.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/12\/kinsta-logo.jpeg\",\"width\":500,\"height\":500,\"caption\":\"Kinsta\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/it\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/kinstaitalia\/\",\"https:\/\/x.com\/Kinsta_IT\",\"https:\/\/www.instagram.com\/kinstahosting\/\",\"https:\/\/www.linkedin.com\/company\/kinsta\/\",\"https:\/\/www.pinterest.com\/kinstahosting\/\",\"https:\/\/www.youtube.com\/c\/Kinsta\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/kinsta.com\/it\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238\",\"name\":\"Leonardo Losoviz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/kinsta.com\/it\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/b28085726ee66e49f08be16ad668efd5?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/b28085726ee66e49f08be16ad668efd5?s=96&d=mm&r=g\",\"caption\":\"Leonardo Losoviz\"},\"description\":\"Leo writes about innovative web development trends, mostly concerning PHP, WordPress and GraphQL. You can find him at leoloso.com and twitter.com\/losoviz.\",\"sameAs\":[\"https:\/\/leoloso.com\",\"https:\/\/x.com\/losoviz\",\"https:\/\/www.youtube.com\/@GatoGraphQL\"],\"url\":\"https:\/\/kinsta.com\/it\/blog\/author\/leonardolosoviz\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Guida Definitiva al Transpiling del Codice PHP","description":"Stanco di lavorare con pi\u00f9 versioni di PHP? Impara a scrivere codice sorgente con PHP 8.0 e convertirlo alle versioni precedenti di PHP.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/","og_locale":"it_IT","og_type":"article","og_title":"Guida Definitiva al Transpiling del Codice PHP","og_description":"Stanco di lavorare con pi\u00f9 versioni di PHP? Impara a scrivere codice sorgente con PHP 8.0 e convertirlo alle versioni precedenti di PHP.","og_url":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/","og_site_name":"Kinsta\u00ae","article_publisher":"https:\/\/www.facebook.com\/kinstaitalia\/","article_published_time":"2021-09-24T13:09:11+00:00","article_modified_time":"2023-03-14T13:35:01+00:00","og_image":[{"width":1460,"height":730,"url":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg","type":"image\/jpeg"}],"author":"Leonardo Losoviz","twitter_card":"summary_large_image","twitter_description":"Stanco di lavorare con pi\u00f9 versioni di PHP? Impara a scrivere codice sorgente con PHP 8.0 e convertirlo alle versioni precedenti di PHP.","twitter_image":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg","twitter_creator":"@losoviz","twitter_site":"@Kinsta_IT","twitter_misc":{"Scritto da":"Leonardo Losoviz","Tempo di lettura stimato":"22 minuti"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#article","isPartOf":{"@id":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/"},"author":{"name":"Leonardo Losoviz","@id":"https:\/\/kinsta.com\/it\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238"},"headline":"Guida Definitiva al Transpiling del Codice PHP","datePublished":"2021-09-24T13:09:11+00:00","dateModified":"2023-03-14T13:35:01+00:00","mainEntityOfPage":{"@id":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/"},"wordCount":3885,"commentCount":0,"publisher":{"@id":"https:\/\/kinsta.com\/it\/#organization"},"image":{"@id":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg","keywords":["php","programming"],"articleSection":["Sviluppo Web"],"inLanguage":"it-IT","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/","url":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/","name":"Guida Definitiva al Transpiling del Codice PHP","isPartOf":{"@id":"https:\/\/kinsta.com\/it\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#primaryimage"},"image":{"@id":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg","datePublished":"2021-09-24T13:09:11+00:00","dateModified":"2023-03-14T13:35:01+00:00","description":"Stanco di lavorare con pi\u00f9 versioni di PHP? Impara a scrivere codice sorgente con PHP 8.0 e convertirlo alle versioni precedenti di PHP.","breadcrumb":{"@id":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#breadcrumb"},"inLanguage":"it-IT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kinsta.com\/it\/blog\/traspiling-php\/"]}]},{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#primaryimage","url":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg","contentUrl":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2021\/09\/transpiling-php.jpg","width":1460,"height":730,"caption":"Guida Definitiva al Transpiling del Codice PHP"},{"@type":"BreadcrumbList","@id":"https:\/\/kinsta.com\/it\/blog\/traspiling-php\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kinsta.com\/it\/"},{"@type":"ListItem","position":2,"name":"Impara PHP","item":"https:\/\/kinsta.com\/it\/argomenti\/impara-php\/"},{"@type":"ListItem","position":3,"name":"Guida Definitiva al Transpiling del Codice PHP"}]},{"@type":"WebSite","@id":"https:\/\/kinsta.com\/it\/#website","url":"https:\/\/kinsta.com\/it\/","name":"Kinsta\u00ae","description":"Soluzioni di hosting premium, veloci e sicure","publisher":{"@id":"https:\/\/kinsta.com\/it\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kinsta.com\/it\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"it-IT"},{"@type":"Organization","@id":"https:\/\/kinsta.com\/it\/#organization","name":"Kinsta","url":"https:\/\/kinsta.com\/it\/","logo":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/kinsta.com\/it\/#\/schema\/logo\/image\/","url":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/12\/kinsta-logo.jpeg","contentUrl":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/12\/kinsta-logo.jpeg","width":500,"height":500,"caption":"Kinsta"},"image":{"@id":"https:\/\/kinsta.com\/it\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/kinstaitalia\/","https:\/\/x.com\/Kinsta_IT","https:\/\/www.instagram.com\/kinstahosting\/","https:\/\/www.linkedin.com\/company\/kinsta\/","https:\/\/www.pinterest.com\/kinstahosting\/","https:\/\/www.youtube.com\/c\/Kinsta"]},{"@type":"Person","@id":"https:\/\/kinsta.com\/it\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238","name":"Leonardo Losoviz","image":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/kinsta.com\/it\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/b28085726ee66e49f08be16ad668efd5?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b28085726ee66e49f08be16ad668efd5?s=96&d=mm&r=g","caption":"Leonardo Losoviz"},"description":"Leo writes about innovative web development trends, mostly concerning PHP, WordPress and GraphQL. You can find him at leoloso.com and twitter.com\/losoviz.","sameAs":["https:\/\/leoloso.com","https:\/\/x.com\/losoviz","https:\/\/www.youtube.com\/@GatoGraphQL"],"url":"https:\/\/kinsta.com\/it\/blog\/author\/leonardolosoviz\/"}]}},"acf":[],"_links":{"self":[{"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/posts\/47870","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/users\/196"}],"replies":[{"embeddable":true,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/comments?post=47870"}],"version-history":[{"count":9,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/posts\/47870\/revisions"}],"predecessor-version":[{"id":66891,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/posts\/47870\/revisions\/66891"}],"alternate":[{"embeddable":true,"hreflang":"en","title":"English","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/47870\/translations\/en"},{"embeddable":true,"hreflang":"es","title":"Spanish","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/47870\/translations\/es"},{"embeddable":true,"hreflang":"it","title":"Italian","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/47870\/translations\/it"},{"embeddable":true,"hreflang":"fr","title":"French","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/47870\/translations\/fr"},{"embeddable":true,"hreflang":"pt","title":"Portuguese","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/47870\/translations\/pt"},{"embeddable":true,"hreflang":"de","title":"German","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/47870\/translations\/de"},{"embeddable":true,"hreflang":"nl","title":"Dutch","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/47870\/translations\/nl"},{"href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/47870\/tree"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/media\/47875"}],"wp:attachment":[{"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/media?parent=47870"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/tags?post=47870"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/topic?post=47870"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}