{"id":44394,"date":"2021-09-30T16:04:51","date_gmt":"2021-09-30T14:04:51","guid":{"rendered":"https:\/\/kinsta.com\/?p=100177"},"modified":"2023-08-22T04:45:45","modified_gmt":"2023-08-22T07:45:45","slug":"transpilacao-php","status":"publish","type":"post","link":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/","title":{"rendered":"O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP"},"content":{"rendered":"<p>Em circunst\u00e2ncias ideais, n\u00f3s devemos usar o <a href=\"https:\/\/kinsta.com\/pt\/changelog\/php-8\/\">PHP 8.0<\/a> (a \u00faltima vers\u00e3o a partir do momento em que escrevemos este artigo) para todos os nossos sites e atualiz\u00e1-lo assim que uma nova vers\u00e3o for lan\u00e7ada. No entanto, os desenvolvedores freq\u00fcentemente precisar\u00e3o trabalhar com vers\u00f5es anteriores do PHP, como ao criar um plugin p\u00fablico para <a href=\"https:\/\/kinsta.com\/pt\/blog\/o-que-wordpress\/\">WordPress<\/a> ou trabalhar com c\u00f3digo antigo que impede a atualiza\u00e7\u00e3o do ambiente do webserver.<\/p>\n<p>Nessas situa\u00e7\u00f5es, n\u00f3s poder\u00edamos perder a esperan\u00e7a de usar o \u00faltimo c\u00f3digo do PHP. Mas h\u00e1 uma alternativa melhor: n\u00f3s ainda podemos escrever nosso c\u00f3digo fonte com o PHP 8.0 e transpilar para uma vers\u00e3o anterior do PHP &#8211; at\u00e9 mesmo para o PHP 7.1.<\/p>\n<p>Neste guia, n\u00f3s lhe ensinaremos tudo o que voc\u00ea precisa saber sobre a transpila\u00e7\u00e3o de c\u00f3digo 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>O que \u00e9 transpila\u00e7\u00e3o?<\/h2>\n<p>Transpila\u00e7\u00e3o ou &#8220;Transpiling em Ingl\u00eas&#8221; converte o c\u00f3digo fonte de uma <a href=\"https:\/\/kinsta.com\/pt\/blog\/melhor-linguagem-de-programacao\/\">linguagem de programa\u00e7\u00e3o<\/a> em um c\u00f3digo fonte equivalente da mesma ou de uma linguagem de programa\u00e7\u00e3o diferente.<\/p>\n<p>Transpila\u00e7\u00e3o n\u00e3o \u00e9 um conceito novo dentro do desenvolvimento web: desenvolvedores do lado do cliente provavelmente estar\u00e3o familiarizados com o <a href=\"https:\/\/babeljs.io\/\" target=\"_blank\" rel=\"noopener noreferrer\">Babel<\/a>, um transpilador de c\u00f3digo JavaScript.<\/p>\n<p>Babel converte o c\u00f3digo JavaScript da moderna vers\u00e3o ECMAScript 2015+ em uma vers\u00e3o antiga e compat\u00edvel com os navegadores inferior . Por exemplo, dada uma fun\u00e7\u00e3o arrow ES2015:<\/p>\n<pre><code class=\"language-js\">[2, 4, 6].map((n) =&gt; n * 2);\n<\/code><\/pre>\n<p>&#8230;Babel ir\u00e1 convert\u00ea-lo em sua vers\u00e3o ES5:<\/p>\n<pre><code class=\"language-js\">[2, 4, 6].map(function(n) {\n  return n * 2;\n});\n<\/code><\/pre>\n<h3>O que \u00e9 transpila\u00e7\u00e3o PHP?<\/h3>\n<p>O que \u00e9 potencialmente novo dentro do desenvolvimento web \u00e9 a possibilidade de transpilar o c\u00f3digo do lado do servidor, em particular o PHP.<\/p>\n<p>A transpila\u00e7\u00e3o do PHP funciona da mesma forma que a transpila\u00e7\u00e3o JavaScript: o c\u00f3digo fonte de uma <a href=\"https:\/\/kinsta.com\/pt\/blog\/versoes-do-php\/\">vers\u00e3o moderna do PHP <\/a> \u00e9 convertido em um c\u00f3digo equivalente para uma vers\u00e3o PHP mais antiga.<\/p>\n<p>Seguindo o mesmo exemplo de antes, uma fun\u00e7\u00e3o arrow do 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>pode ser transpiladas para sua vers\u00e3o equivalente do 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);\n<\/code><\/pre>\n<p>As fun\u00e7\u00f5es arrows podem ser transpiladas porque s\u00e3o <a href=\"https:\/\/en.wikipedia.org\/wiki\/Syntactic_sugar\" target=\"_blank\" rel=\"noopener noreferrer\">syntactic sugar<\/a>, ou seja, uma nova sintaxe para produzir um comportamento existente. Este \u00e9 o fruto de baixa suspens\u00e3o.<\/p>\n<p>Entretanto, h\u00e1 tamb\u00e9m novas funcionalidades que criam um novo comportamento e, como tal, n\u00e3o haver\u00e1 c\u00f3digo equivalente para as vers\u00f5es anteriores do PHP. Esse \u00e9 o caso dos <a href=\"https:\/\/kinsta.com\/pt\/blog\/php-8\/#union-types-2-0\">tipos de uni\u00e3o<\/a>, introduzidos no PHP 8.0:<\/p>\n<pre><code class=\"language-php\">function someFunction(float|int $param): string|float|int|null\n{\n  \/\/ ...\n}\n<\/code><\/pre>\n<p>Nessas situa\u00e7\u00f5es, a transpila\u00e7\u00e3o ainda pode ser feita desde que o novo recurso seja necess\u00e1rio para o desenvolvimento, mas n\u00e3o para a produ\u00e7\u00e3o. Ent\u00e3o, n\u00f3s podemos simplesmente remover o recurso completamente do c\u00f3digo transpilado sem conseq\u00fc\u00eancias s\u00e9rias.<\/p>\n<p>Um desses exemplos s\u00e3o os tipos de uni\u00e3o. Este recurso \u00e9 usado para verificar se n\u00e3o h\u00e1 uma incompatibilidade entre o tipo de entrada e o valor fornecido, o que ajuda a prevenir bugs. Se houver um conflito com os tipos, haver\u00e1 um erro j\u00e1 em desenvolvimento e n\u00f3s devemos peg\u00e1-lo e corrigi-lo antes que o c\u00f3digo chegue \u00e0 produ\u00e7\u00e3o.<\/p>\n<p>Portanto, podemos nos dar ao luxo de remover o recurso do c\u00f3digo para produ\u00e7\u00e3o:<\/p>\n<pre><code class=\"language-php\">function someFunction($param)\n{\n  \/\/ ...\n}\n<\/code><\/pre>\n<p>Se o erro ainda acontecer na produ\u00e7\u00e3o, a mensagem de erro lan\u00e7ada ser\u00e1 menos precisa do que se tiv\u00e9ssemos tipos de uni\u00e3o. No entanto, esta desvantagem potencial \u00e9 compensada pela capacidade de usar tipos de uni\u00e3o em primeiro lugar.<\/p>\n\n<h2>Vantagens da transpila\u00e7\u00e3o do C\u00f3digo PHP<\/h2>\n<p>A transpila\u00e7\u00e3o permite codificar um aplicativo usando a \u00faltima vers\u00e3o do PHP e produzir uma vers\u00e3o que tamb\u00e9m funciona em ambientes que executam vers\u00f5es mais antigas do PHP.<\/p>\n<p>Isto pode ser particularmente \u00fatil para desenvolvedores que criam produtos antigo para o\u00a0<a href=\"https:\/\/kinsta.com\/pt\/blog\/sistema-de-gerenciamento-de-conteudo\/\">content management systems (CMS)<\/a>. O WordPress, por exemplo, ainda <a href=\"https:\/\/wordpress.org\/about\/requirements\/\" target=\"_blank\" rel=\"noopener noreferrer\">suporta oficialmente o PHP 5.6<\/a> (apesar de recomendar o PHP 7.4+). A porcentagem de sites WordPress rodando vers\u00f5es PHP 5.6 a 7.2 &#8211; que todos est\u00e3o no Fim de vida &#8220;End-of-Life (EOL)&#8221;, significando que eles n\u00e3o est\u00e3o mais recebendo atualiza\u00e7\u00f5es de seguran\u00e7a &#8211; \u00e9 de 34,8%, e aqueles rodando em qualquer vers\u00e3o PHP que n\u00e3o seja a 8.0 \u00e9 de 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\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/07\/wp-stats.png\" alt=\"Estat\u00edsticas de uso do WordPress por vers\u00e3o. Fonte da imagem\" width=\"920\" height=\"720\"><\/a><figcaption class=\"wp-caption-text\">Estat\u00edsticas de uso do WordPress por vers\u00e3o. Fonte da imagem: <a href=\"https:\/\/wordpress.org\/about\/stats\/\" target=\"_blank\" rel=\"noopener noreferrer\">WordPress<\/a><\/figcaption><\/figure>\n<p>Consequentemente, os temas e plugins do WordPress direcionados a uma audi\u00eancia global provavelmente ser\u00e3o codificados com uma vers\u00e3o antiga do PHP para aumentar seu poss\u00edvel alcance. Gra\u00e7as \u00e0 transpila\u00e7\u00e3o, estes poderiam ser codificados usando PHP 8.0, e ainda ser lan\u00e7ados para uma vers\u00e3o mais antiga do PHP, visando assim o maior n\u00famero poss\u00edvel de usu\u00e1rios.<\/p>\n<p>De fato, qualquer aplicativo que precise suportar qualquer vers\u00e3o PHP que n\u00e3o seja a mais recente (mesmo dentro da faixa das vers\u00f5es PHP atualmente suportadas) pode se beneficiar.<\/p>\n<p>Este \u00e9 o caso do Drupal, que <a href=\"https:\/\/www.drupal.org\/docs\/system-requirements\/php-requirements\" target=\"_blank\" rel=\"noopener noreferrer\">requer o PHP 7.3<\/a>. Gra\u00e7as \u00e0 transpila\u00e7\u00e3o, os desenvolvedores podem criar m\u00f3dulos Drupal dispon\u00edveis publicamente usando o PHP 8.0, e liber\u00e1-los com o PHP 7.3.<\/p>\n<p>Outro exemplo \u00e9 quando se cria c\u00f3digo personalizado para clientes que n\u00e3o podem executar o PHP 8.0 em seus ambientes devido a uma raz\u00e3o ou outra. No entanto, gra\u00e7as \u00e0 transpila\u00e7\u00e3o, os desenvolvedores ainda podem codificar seus produtos usando PHP 8.0 e execut\u00e1-los nesses ambientes mais antigos.<\/p>\n<h3>Quando Transpilar o PHP<\/h3>\n<p>O c\u00f3digo PHP sempre pode ser transpilado a menos que contenha algum recurso PHP que n\u00e3o tenha equivalente na vers\u00e3o anterior do PHP.<\/p>\n<p>Esse \u00e9 possivelmente o caso dos <a href=\"https:\/\/kinsta.com\/pt\/blog\/php-8\/#attributes\">atributos<\/a>, introduzidos no PHP 8.0:<\/p>\n<pre><code class=\"language-php\">#[SomeAttr]\nfunction someFunc() {}\n\n#[AnotherAttr]\nclass SomeClass {}\n<\/code><\/pre>\n<p>No exemplo anterior, usando fun\u00e7\u00f5es arrow, o c\u00f3digo podia ser transpilado porque as fun\u00e7\u00f5es arrow s\u00e3o syntactic sugar. Atributos, em contraste, criam um comportamento completamente novo. Este comportamento tamb\u00e9m poderia ser reproduzido com o PHP 7.4 ou abaixo, mas apenas codificando manualmente, ou seja, n\u00e3o automaticamente baseado em uma ferramenta ou processo (IA poderia fornecer uma solu\u00e7\u00e3o, mas n\u00f3s ainda n\u00e3o estamos l\u00e1).<\/p>\n<p>Atributos destinados ao uso em desenvolvimento, tais como <code><a href=\"https:\/\/wiki.php.net\/rfc\/deprecated_attribute\">#[<\/a><a href=\"https:\/\/wiki.php.net\/rfc\/deprecated_attribute\">Deprecated<\/a>]<\/code> , podem ser removidos da mesma forma que os tipos de uni\u00e3o s\u00e3o removidos. Mas os atributos que modificam o comportamento do aplicativo na produ\u00e7\u00e3o n\u00e3o podem ser removidos, e tamb\u00e9m n\u00e3o podem ser transpiladas diretamente.<\/p>\n<p>A partir de hoje, nenhum transpilador &#8220;transpiler em Ingl\u00eas&#8221; pode pegar c\u00f3digo com atributos no PHP 8.0 e produzir automaticamente seu c\u00f3digo equivalente no PHP 7.4. Consequentemente, se o seu c\u00f3digo PHP precisa usar atributos, ent\u00e3o a sua transpila\u00e7\u00e3o ser\u00e1 dif\u00edcil ou invi\u00e1vel.<\/p>\n<h3>Funcionalidades PHP que podem ser transpiladas<\/h3>\n<p>Estas s\u00e3o as funcionalidades do PHP 7.1 ou acima que podem ser transpiladas atualmente. Se o seu c\u00f3digo s\u00f3 usa estes recursos, voc\u00ea pode ter a certeza de que seu aplicativo transposta ir\u00e1 funcionar. Caso contr\u00e1rio, voc\u00ea precisar\u00e1 avaliar se o c\u00f3digo transpilado ir\u00e1 produzir falhas.<\/p>\n<table>\n<thead>\n<tr>\n<th>Vers\u00e3o PHP<\/th>\n<th>Funcionalidades<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>7.1<\/td>\n<td>Tudo<\/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<code>object<\/code><\/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\">Parameter type widening<\/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\"><code>PREG_UNMATCHED_AS_NULL<\/code> flag em <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\">Atribui\u00e7\u00f5es de refer\u00eancia em <code>list()<\/code><\/a> \/ desestrutura\u00e7\u00e3o de array <em>(Exceto dentro do <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\">Sintaxe flex\u00edvel de Heredoc e Nowdoc<\/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\">Chamadas de fun\u00e7\u00f5es com v\u00edrgulas de rastreamento<\/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> aceita argumento $op\u00e7\u00e3o<\/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\">Propriedades datilografadas<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/functions.arrow.php\" target=\"_blank\" rel=\"noopener noreferrer\">Fun\u00e7\u00f5es arrow<\/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\">Operador de coalesc\u00eancia nula<\/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\">Desembalando dentro de arrays<\/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\">Separador num\u00e9rico literal<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.php.net\/manual\/en\/migration74.new-features.php#migration74.new-features.standard.strip-tags\"><code>strip_tags()<\/code> com array de nomes de tags<\/a><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\">tipos de retorno covariantes e param tipos contravariantes<\/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\">Tipo Uni\u00e3o<\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/mixed-type\" target=\"_blank\" rel=\"noopener noreferrer\">Pseudo-tipos<code>mixed<\/code><\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/static-return-type\" target=\"_blank\" rel=\"noopener noreferrer\">Tipo retorno <code>static<\/code><\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/class-constant-on-objects\">Constante m\u00e1gica nos objetos <\/a><a href=\"https:\/\/php.watch\/versions\/8.0\/class-constant-on-objects\"><code>::class<\/code><\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/match-expression\" target=\"_blank\" rel=\"noopener noreferrer\">express\u00f5es <code>match<\/code><\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/catch-exception-type\">Exce\u00e7\u00f5es somente por tipo <\/a><a href=\"https:\/\/php.watch\/versions\/8.0\/catch-exception-type\"><code>catch<\/code><\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/null-safe-operator\" target=\"_blank\" rel=\"noopener noreferrer\">Operador seguro para todos<\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/constructor-property-promotion\" target=\"_blank\" rel=\"noopener noreferrer\">Promo\u00e7\u00e3o de propriedade de construtores de classe<\/a><br \/>\n&#8211; <a href=\"https:\/\/php.watch\/versions\/8.0\/trailing-comma-parameter-use-list\" target=\"_blank\" rel=\"noopener noreferrer\">V\u00edrgulas de rastreamento em listas de par\u00e2metros e listas <code>use<\/code> de fechamento<\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Transpiladores PHP<\/h2>\n<p>Atualmente, existe uma ferramenta para a transpila\u00e7\u00e3o de c\u00f3digo PHP: <a href=\"https:\/\/github.com\/rectorphp\/rector\">Rector<\/a>.<\/p>\n<p>Rector \u00e9 uma ferramenta reconstrutora de PHP, que converte c\u00f3digo PHP baseado em regras program\u00e1veis. N\u00f3s inserimos o c\u00f3digo fonte e o <a href=\"https:\/\/github.com\/rectorphp\/rector\/blob\/main\/docs\/rector_rules_overview.md\" target=\"_blank\" rel=\"noopener noreferrer\">conjunto de regras<\/a> a serem executadas, e Rector transformar\u00e1 o c\u00f3digo.<\/p>\n<p>O Rector \u00e9 operado via linha de comando, instalado no projeto via Composer. Quando executado, o Rector ir\u00e1 emitir um &#8220;diff&#8221; (adi\u00e7\u00f5es em verde, remo\u00e7\u00f5es em vermelho) do c\u00f3digo antes e depois da convers\u00e3o:<\/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\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/07\/rector-process-dry-run.gif\" alt=\"Sa\u00edda \"diff\" do Rector\" width=\"740\" height=\"480\"><\/a><figcaption class=\"wp-caption-text\">Sa\u00edda &#8220;diff&#8221; do Rector<\/figcaption><\/figure>\n<h2>Qual vers\u00e3o do PHP que pode ser transpilada<\/h2>\n<p>Para transpilar o c\u00f3digo atrav\u00e9s das vers\u00f5es PHP, as regras correspondentes devem ser criadas.<\/p>\n<p>Hoje, a biblioteca do Rector inclui a maioria das regras para a transpila\u00e7\u00e3o de c\u00f3digo dentro da faixa do PHP 8.0 a 7.1. Portanto, n\u00f3s podemos transpilar de forma confi\u00e1vel nosso c\u00f3digo PHP at\u00e9 a vers\u00e3o 7.1.<\/p>\n<p>H\u00e1 tamb\u00e9m <a href=\"https:\/\/github.com\/rectorphp\/rector\/blob\/main\/docs\/rector_rules_overview.md#downgradephp71\" target=\"_blank\" rel=\"noopener noreferrer\">regras para a transpila\u00e7\u00e3o do PHP 7.1 para 7.0<\/a> e <a href=\"https:\/\/github.com\/rectorphp\/rector\/blob\/main\/docs\/rector_rules_overview.md#downgradephp70\" target=\"_blank\" rel=\"noopener noreferrer\">de 7.0 para 5.6<\/a>, mas estas n\u00e3o s\u00e3o exaustivas. O trabalho est\u00e1 em andamento para complet\u00e1-las, ent\u00e3o n\u00f3s podemos eventualmente transpilar o c\u00f3digo PHP para a vers\u00e3o 5.6.<\/p>\n<h2>Transpila\u00e7\u00e3o vs. Backporting<\/h2>\n<p>O backporting \u00e9 similar ao transpila\u00e7\u00e3o &#8220;transpiling em Ingl\u00eas&#8221;, mas mais simples. O c\u00f3digo de backporting n\u00e3o necessariamente depende de novas funcionalidades de uma linguagem. Ao inv\u00e9s disso, a mesma funcionalidade pode ser fornecida para uma vers\u00e3o antiga da linguagem simplesmente copiando\/colando\/adaptando o c\u00f3digo correspondente da nova vers\u00e3o da linguagem.<\/p>\n<p>Por exemplo, a fun\u00e7\u00e3o <code>str_contains<\/code> foi introduzida no PHP 8.0. A mesma fun\u00e7\u00e3o para o PHP 7.4 e abaixo pode ser facilmente implementada desta forma:<\/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}\n<\/code><\/pre>\n<p>Porque backporting \u00e9 mais simples do que transpilar, n\u00f3s devemos optar por esta solu\u00e7\u00e3o sempre que o backporting fizer o trabalho.<\/p>\n<p>Com rela\u00e7\u00e3o \u00e0 faixa entre PHP 8.0 e 7.1, n\u00f3s podemos usar as bibliotecas polifill da <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>Estas bibliotecas suportam as seguintes fun\u00e7\u00f5es, classes, constantes e interfaces:<\/p>\n<table style=\"height: 1173px\" width=\"335\">\n<thead>\n<tr>\n<th>Vers\u00e3o PHP<\/th>\n<th>Caracter\u00edsticas<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>7.2<\/td>\n<td>Fun\u00e7\u00f5es:<\/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>Constantes:<\/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>Fun\u00e7\u00f5es:<\/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>Exce\u00e7\u00f5es:<\/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>Fun\u00e7\u00f5es:<\/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>Interfaces:<\/p>\n<ul>\n<li><code>Stringable<\/code><\/li>\n<\/ul>\n<p>Classes:<\/p>\n<ul>\n<li><code>ValueError<\/code><\/li>\n<li><code>UnhandledMatchError<\/code><\/li>\n<\/ul>\n<p>Constantes:<\/p>\n<ul>\n<li><code>FILTER_VALIDATE_BOOL<\/code><\/li>\n<\/ul>\n<p>Fun\u00e7\u00f5es:<\/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>Exemplos de PHP transpilado<\/h2>\n<p>Vamos inspecionar alguns exemplos de c\u00f3digo PHP transpilado, e alguns pacotes que est\u00e3o sendo totalmente transpilados.<\/p>\n<h3>C\u00f3digo PHP<\/h3>\n<p>A express\u00e3o\u00a0 <code>match<\/code> foi <a href=\"https:\/\/kinsta.com\/pt\/blog\/php-8\/#match-expression\">introduzida no PHP 8.0<\/a>. Este c\u00f3digo fonte:<\/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;ser\u00e1 transpilada para sua vers\u00e3o equivalente do PHP 7.4, usando o operador <code>switch<\/code>:<\/p>\n<pre><code class=\"language-php\">function getFieldValue(string $fieldName): ?string\n{\n  switch ($fieldName) {\n    case 'foo':\n      return 'foofoo';\n    case 'bar':\n      return 'barbar';\n    case 'baz':\n      return 'bazbaz';\n    default:\n      return null;\n  }\n}\n<\/code><\/pre>\n<p>O <a href=\"https:\/\/kinsta.com\/pt\/blog\/php-8\/#nullsafe-operator\">operador nullsafe<\/a> tamb\u00e9m foi introduzido no 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>O c\u00f3digo transpilado precisa primeiro atribuir o valor da opera\u00e7\u00e3o a uma nova vari\u00e1vel, para evitar executar a opera\u00e7\u00e3o duas vezes:<\/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>O recurso de <a href=\"https:\/\/kinsta.com\/pt\/blog\/php-8\/#constructor-property-promotion\">promo\u00e7\u00e3o de propriedade do construtor<\/a>, tamb\u00e9m introduzido no PHP 8.0, permite que os desenvolvedores escrevam menos c\u00f3digo:<\/p>\n<pre><code class=\"language-php\">class QueryResolver\n{\n  function __construct(protected QueryFormatter $queryFormatter)\n  {\n  }\n}\n<\/code><\/pre>\n<p>Ao transpilar para o PHP 7.4, o c\u00f3digo completo \u00e9 produzido:<\/p>\n<pre><code class=\"language-php\"> class QueryResolver\n {\n  protected QueryFormatter $queryFormatter;\n\n  function __construct(QueryFormatter $queryFormatter)\n  {\n    $this-&gt;queryFormatter = $queryFormatter;\n  }\n}\n<\/code><\/pre>\n<p>O c\u00f3digo transpilado acima cont\u00e9m <a href=\"https:\/\/kinsta.com\/pt\/blog\/php-7-4\/#typed-properties\">propriedades digitadas<\/a>, que foram introduzidas no PHP 7.4. A transpila\u00e7\u00e3o desse c\u00f3digo para o PHP 7.3 os substitui por blocos de documentos:<\/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}\n<\/code><\/pre>\n<h3>Pacotes PHP<\/h3>\n<p>As seguintes bibliotecas est\u00e3o sendo transpiladas para a produ\u00e7\u00e3o:<\/p>\n<table>\n<thead>\n<tr>\n<th>Biblioteca\/descri\u00e7\u00e3o<\/th>\n<th>C\u00f3digo\/notas<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/getrector.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">Rector<\/a><br \/>\nFerramenta reconstrutora de PHP que torna a transpila\u00e7\u00e3o poss\u00edvel<\/td>\n<td>&#8211; <a href=\"https:\/\/github.com\/rectorphp\/rector-src\" target=\"_blank\" rel=\"noopener noreferrer\">C\u00f3digo fonte<\/a><br \/>\n&#8211; <a href=\"https:\/\/github.com\/rectorphp\/rector\" target=\"_blank\" rel=\"noopener noreferrer\">C\u00f3digo transpilado<\/a><br \/>\n&#8211; <a href=\"https:\/\/getrector.org\/blog\/prefixed-rector-by-default\" target=\"_blank\" rel=\"noopener noreferrer\">Notas<\/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 \/>\nFerramenta para que o c\u00f3digo PHP adere a um conjunto de regras<\/td>\n<td>&#8211; <a href=\"https:\/\/github.com\/symplify\/symplify\/tree\/main\/packages\/easy-coding-standard\" target=\"_blank\" rel=\"noopener noreferrer\">C\u00f3digo fonte<\/a><br \/>\n&#8211; <a href=\"https:\/\/github.com\/symplify\/easy-coding-standard\" target=\"_blank\" rel=\"noopener noreferrer\">C\u00f3digo transpilado<\/a><br \/>\n&#8211; <a href=\"https:\/\/tomasvotruba.com\/blog\/introducing-ecs-prefixed-and-downgraded-to-php-71\/\" target=\"_blank\" rel=\"noopener noreferrer\">Notas<\/a><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/graphql-api.com\" target=\"_blank\" rel=\"noopener noreferrer\">API GraphQL para WordPress<\/a><br \/>\nPlugin fornecendo um servidor GraphQL para 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\">C\u00f3digo fonte<\/a><br \/>\n&#8211; <a href=\"https:\/\/github.com\/GraphQLAPI\/graphql-api-for-wp-dist\/\" target=\"_blank\" rel=\"noopener noreferrer\">C\u00f3digo transpilado<\/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\">Notas<\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Pr\u00f3s e Contras da transpila\u00e7\u00e3o do PHP<\/h2>\n<p>O benef\u00edcio de transpilar o PHP j\u00e1 foi descrito: ele permite que o c\u00f3digo fonte utilize o PHP 8.0 (ou seja, a \u00faltima vers\u00e3o do PHP), que ser\u00e1 transformado em uma vers\u00e3o inferior para que o PHP seja executado em um aplicativo ou ambiente inferior.<\/p>\n<p>Isto nos permite efetivamente nos tornarmos melhores desenvolvedores, produzindo c\u00f3digo com maior qualidade. Isto porque nosso c\u00f3digo fonte pode usar os tipos de uni\u00e3o (Union Type) do PHP 8.0, as propriedades digitadas do PHP 7.4, e os diferentes tipos e pseudo-tipos adicionados a cada nova vers\u00e3o do PHP (<code>mixed<\/code> a partir do PHP 8.0, <code>object<\/code> do PHP 7.2), entre outras funcionalidades modernas do PHP.<\/p>\n<p>Usando estas funcionalidades, podemos capturar melhor os bugs durante o desenvolvimento e escrever c\u00f3digo que \u00e9 mais f\u00e1cil de ler.<\/p>\n<p>Agora, vamos dar uma olhada nos inconvenientes.<\/p>\n<h3>Deve ser codificado e atualizado<\/h3>\n<p>O rector pode transportar o c\u00f3digo automaticamente, mas o processo provavelmente exigir\u00e1 alguma entrada manual para que ele funcione com nossa configura\u00e7\u00e3o espec\u00edfica.<\/p>\n<h3>Bibliotecas de terceiros tamb\u00e9m precisam ser transpiladas<\/h3>\n<p>Isto se torna um problema sempre que transpilados produzem erros, j\u00e1 que devemos ent\u00e3o mergulhar no c\u00f3digo fonte deles para descobrir a raz\u00e3o poss\u00edvel. Se o problema puder ser resolvido e o projeto for de c\u00f3digo aberto, n\u00f3s precisaremos enviar um pedido pull. Se a biblioteca n\u00e3o for de c\u00f3digo aberto, n\u00f3s podemos chegar a um roadblock.<\/p>\n<h3>O Rector n\u00e3o nos informa quando o c\u00f3digo n\u00e3o pode ser transpilado<\/h3>\n<p>Se o c\u00f3digo fonte cont\u00e9m atributos PHP 8.0 ou qualquer outra funcionalidade que n\u00e3o pode ser transpilada, n\u00f3s n\u00e3o podemos prosseguir. Entretanto, o Rector n\u00e3o ir\u00e1 verificar esta condi\u00e7\u00e3o, ent\u00e3o precisamos fazer isso manualmente. Isto pode n\u00e3o ser um grande problema em rela\u00e7\u00e3o ao nosso pr\u00f3prio c\u00f3digo fonte, uma vez que j\u00e1 estamos familiarizados com ele, mas pode se tornar um obst\u00e1culo em rela\u00e7\u00e3o \u00e0s depend\u00eancias de terceiros.<\/p>\n<h3>A informa\u00e7\u00e3o de depura\u00e7\u00e3o utiliza o c\u00f3digo transpilado, e n\u00e3o o c\u00f3digo fonte<\/h3>\n<p>Quando o aplicativo produz uma mensagem de erro com um rastreamento de pilha na produ\u00e7\u00e3o, o n\u00famero da linha ir\u00e1 apontar para o c\u00f3digo transpilado. N\u00f3s precisamos converter de volta do c\u00f3digo transpilado para o c\u00f3digo original para encontrar o n\u00famero de linha correspondente no c\u00f3digo fonte.<\/p>\n<h3>O c\u00f3digo transpilado tamb\u00e9m deve ser prefixado<\/h3>\n<p>Nosso projeto transpilado e algumas outras bibliotecas tamb\u00e9m instaladas no ambiente de produ\u00e7\u00e3o poderiam usar a mesma depend\u00eancia de terceiros. Esta depend\u00eancia de terceiros ser\u00e1 transpilada para o nosso projeto e manter\u00e1 seu c\u00f3digo fonte original para a outra biblioteca. Portanto, a vers\u00e3o transpilada deve ser prefixada via <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>, ou alguma outra ferramenta para evitar poss\u00edveis conflitos.<\/p>\n<h3>A transpila\u00e7\u00e3o deve ser feita durante a integra\u00e7\u00e3o cont\u00ednua (CI &#8211; Continuous Integration)<\/h3>\n<p>Como o c\u00f3digo transpilado ir\u00e1 naturalmente substituir o c\u00f3digo fonte, n\u00e3o devemos executar o processo de transpila\u00e7\u00e3o em nossos computadores de desenvolvimento, ou corremos o risco de criar efeitos colaterais. Executar o processo durante a execu\u00e7\u00e3o de um CI \u00e9 mais adequado (mais sobre isso abaixo).<\/p>\n<h2>Como transpilar o PHP<\/h2>\n<p>Primeiro, n\u00f3s precisamos instalar o Rector em nosso projeto de desenvolvimento:<\/p>\n<pre><code class=\"language-bash\">composer require rector\/rector --dev\n<\/code><\/pre>\n<p>Ent\u00e3o criamos um arquivo de configura\u00e7\u00e3o <code>rector.php<\/code> no diret\u00f3rio raiz do projeto contendo os conjuntos de regras necess\u00e1rios. Para baixar o c\u00f3digo do PHP 8.0 para 7.1, n\u00f3s usamos esta configura\u00e7\u00e3o:<\/p>\n<pre><code class=\"language-php\">use Rector\\Set\\ValueObject\\DowngradeSetList;\nuse 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>Para garantir que o processo seja executado como esperado, podemos executar o comando <code>process<\/code> do Rector em modo seco, passando o(s) local(is) a processar (neste caso, todos os arquivos sob a pasta <code>src\/<\/code>):<\/p>\n<pre><code class=\"language-bash\">vendor\/bin\/rector process src --dry-run\n<\/code><\/pre>\n<p>Para realizar a transpila\u00e7\u00e3o, n\u00f3s executamos o comando <code>process<\/code> do Rector, que modificar\u00e1 os arquivos dentro de sua localiza\u00e7\u00e3o existente:<\/p>\n<pre><code class=\"language-bash\">vendor\/bin\/retor process src\n<\/code><\/pre>\n<p>Por favor note: se rodarmos o <code>rector process<\/code>\u00a0em nossos computadores de desenvolvimento, o c\u00f3digo fonte ser\u00e1 convertido no lugar, sob <code>src\/<\/code>. Entretanto, n\u00f3s queremos produzir o c\u00f3digo convertido em um local diferente para n\u00e3o sobrepor o c\u00f3digo fonte quando o c\u00f3digo for baixado. Por esta raz\u00e3o, rodar o processo \u00e9 mais adequado durante a integra\u00e7\u00e3o cont\u00ednua.<\/p>\n<h2>Otimizando o processo de transpila\u00e7\u00e3o<\/h2>\n<p>Para gerar um deliverable transpiled para produ\u00e7\u00e3o, apenas o c\u00f3digo para produ\u00e7\u00e3o deve ser convertido; o c\u00f3digo necess\u00e1rio apenas para desenvolvimento pode ser pulado. Isso significa que podemos evitar a transpila\u00e7\u00e3o de todos os testes (tanto para nosso projeto quanto para suas depend\u00eancias) e todas as depend\u00eancias para desenvolvimento.<\/p>\n<p>Com rela\u00e7\u00e3o aos testes, n\u00f3s j\u00e1 saberemos onde est\u00e3o localizados os testes para o nosso projeto &#8211; por exemplo, sob a pasta <code>tests\/<\/code>. Tamb\u00e9m devemos saber onde est\u00e3o os tests das depend\u00eancias &#8211; por exemplo, sob suas subpastas <code>tests\/<\/code>, <code>test\/<\/code> e <code>Test\/<\/code> (para diferentes bibliotecas). Ent\u00e3o, n\u00f3s dizemos ao Rector para pular o processamento dessas pastas:<\/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};\n<\/code><\/pre>\n<p>Com rela\u00e7\u00e3o \u00e0s depend\u00eancias, Composer sabe quais s\u00e3o para desenvolvimento (aqueles sob entrada <code>require-dev<\/code> no <code>composer.json<\/code>) e quais s\u00e3o para produ\u00e7\u00e3o (aqueles sob entrada <code>require<\/code>).<\/p>\n<p>Para recuperar do Composer os caminhos de todas as depend\u00eancias para a produ\u00e7\u00e3o, n\u00f3s executamos:<br \/>\nEste comando produzir\u00e1 uma lista de depend\u00eancias com seu nome e caminho, como esta:<\/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>N\u00f3s podemos extrair todos os caminhos e aliment\u00e1-los com o comando do Rector, que ent\u00e3o processar\u00e1 a pasta <code>src\/<\/code> do nosso projeto mais aquelas pastas contendo todas as depend\u00eancias para produ\u00e7\u00e3o:<\/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\n<\/code><\/pre>\n<p>Uma melhoria adicional pode impedir que o Rector processe aquelas depend\u00eancias que j\u00e1 utilizam a vers\u00e3o alvo do PHP. Se uma biblioteca foi codificada com o PHP 7.1 (ou qualquer vers\u00e3o abaixo), ent\u00e3o n\u00e3o h\u00e1 necessidade de transpilar para o PHP 7.1.<\/p>\n<p>Para conseguir isso, n\u00f3s podemos obter a lista de bibliotecas que requerem PHP 7.2 ou superior e processar apenas aquelas. N\u00f3s obteremos os nomes de todas essas bibliotecas atrav\u00e9s do comando <code>why-not<\/code> do Composer, como este:<\/p>\n<pre><code class=\"language-bash\">composer why-not php \"7.1.*\" | grep -o \"\\S*\\\/\\S*\"\n<\/code><\/pre>\n<p>Como este comando n\u00e3o funciona com a flag\u00a0 <code>--no-dev<\/code>, para incluir apenas depend\u00eancias para produ\u00e7\u00e3o, precisamos primeiro remover as depend\u00eancias para desenvolvimento e regenerar o autoloader, executar o comando, e ent\u00e3o adicion\u00e1-las novamente:<\/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\n<\/code><\/pre>\n<p>O comando <code>info --path<\/code> do Composer recupera o caminho para um pacote, com este 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>N\u00f3s executamos este comando para todos os itens da nossa lista para obter todos os caminhos a serem transpilados:<\/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\n<\/code><\/pre>\n<p>Finalmente, n\u00f3s fornecemos esta lista para o Rector (mais a pasta <code>src\/<\/code> do projeto):<\/p>\n<pre><code class=\"language-bash\">vendor\/bin\/rector process src $paths\n<\/code><\/pre>\n<h2>Armadilhas a serem evitadas durante a transpila\u00e7\u00e3o do c\u00f3digo<\/h2>\n<p>A transpila\u00e7\u00e3o do c\u00f3digo pode ser considerado uma arte, muitas vezes exigindo ajustes espec\u00edficos para o projeto. Vamos ver alguns problemas que podemos ter.<\/p>\n<h3>Regra da cadeia nem sempre \u00e9 processada<\/h3>\n<p>Uma regra da cadeia \u00e9 quando uma regra precisa converter o c\u00f3digo produzido por uma regra anterior.<\/p>\n<p>Por exemplo, a biblioteca <code>symfony\/cache<\/code> cont\u00e9m <a href=\"https:\/\/github.com\/symfony\/cache\/blob\/be5707f\/CacheItem.php#L115\" target=\"_blank\" rel=\"noopener noreferrer\">este c\u00f3digo<\/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}\n<\/code><\/pre>\n<p>Ao transpilar do PHP 7.4 para 7.3, a <code>tag<\/code> de fun\u00e7\u00e3o deve sofrer duas modifica\u00e7\u00f5es:<\/p>\n<ul>\n<li>O tipo de retorno <code>ItemInterface<\/code> deve ser primeiro convertido em <code>self<\/code>, devido \u00e0 regra <a href=\"https:\/\/github.com\/rectorphp\/rector-src\/blob\/f451b0b\/rules\/DowngradePhp74\/Rector\/ClassMethod\/DowngradeCovariantReturnTypeRector.php\"><code>DowngradeCovariantReturnTypeRector<\/code><\/a><\/li>\n<li>O tipo de retorno <code>self<\/code> deve ent\u00e3o ser removido, devido \u00e0 regra <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>O resultado final deve ser este aqui:<\/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>No entanto, o Rector s\u00f3 produz o est\u00e1gio intermedi\u00e1rio:<\/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}\n<\/code><\/pre>\n<p>A quest\u00e3o \u00e9 que o <a href=\"https:\/\/github.com\/rectorphp\/rector\/issues\/5962\" target=\"_blank\" rel=\"noopener noreferrer\">Rector nem sempre pode controlar a ordem na qual as regras s\u00e3o aplicadas<\/a>.<\/p>\n<p>A solu\u00e7\u00e3o \u00e9 identificar quais regra da cadeia foram deixadas sem processamento e executar uma nova corrida do Rector para aplic\u00e1-las.<\/p>\n<p>Para identificar a regra de cadeia, n\u00f3s executamos o Rector duas vezes no c\u00f3digo fonte:<\/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>A primeira vez, n\u00f3s executamos o Rector, como esperado, para executar a transpila\u00e7\u00e3o. Na segunda vez, n\u00f3s usamos a flag <code>--dry-run<\/code> para descobrir se ainda h\u00e1 mudan\u00e7as a serem feitas. Se houver, o comando sair\u00e1 com um c\u00f3digo de erro, e a sa\u00edda &#8220;diff&#8221; indicar\u00e1 qual regra(s) ainda pode(m) ser aplicada(s). Isso significaria que a primeira execu\u00e7\u00e3o n\u00e3o foi completa, com alguma regra de cadeia n\u00e3o sendo processada.<\/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\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/07\/rector-process-run-dry.png\" alt=\"Rector de Corrida com bandeira --dry-run\" width=\"901\" height=\"903\"><\/a><figcaption class=\"wp-caption-text\">Rector de Corrida com flag &#8211;dry-run<\/figcaption><\/figure>\n<p>Uma vez que tenhamos identificado a regra da cadeia (ou chained rule) n\u00e3o aplicada, podemos ent\u00e3o criar outro arquivo de configura\u00e7\u00e3o do Rector &#8211; por exemplo, o <code>rector-chained-rule.php<\/code> executar\u00e1 a regra que falta. Ao inv\u00e9s de processar um conjunto completo de regras para todos os arquivos sob <code>src\/<\/code>, desta vez, podemos executar a regra espec\u00edfica que est\u00e1 faltando no arquivo espec\u00edfico onde ela precisa ser aplicada:<\/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>Finalmente, n\u00f3s dizemos ao Rector em seu segundo passe para usar o novo arquivo de configura\u00e7\u00e3o via 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\n<\/code><\/pre>\n<h3>Depend\u00eancias do Composer podem ser inconsistentes<\/h3>\n<p>As bibliotecas poderiam declarar uma depend\u00eancia para desenvolvimento (ou seja, sob <code>require-dev<\/code> no <code>composer.json<\/code>), ainda assim, referenciar algum c\u00f3digo delas para produ\u00e7\u00e3o (como em alguns arquivos sob <code>src\/<\/code>, n\u00e3o <code>tests\/<\/code>).<\/p>\n<p>Normalmente, isso n\u00e3o \u00e9 um problema porque esse c\u00f3digo pode n\u00e3o ser carregado na produ\u00e7\u00e3o, ent\u00e3o nunca haver\u00e1 um erro no aplicativo. Entretanto, quando o Rector processa o c\u00f3digo fonte e suas depend\u00eancias, ele valida que todo o c\u00f3digo referenciado pode ser carregado. Rector ir\u00e1 lan\u00e7ar um erro se algum arquivo fizer refer\u00eancia a algum trecho de c\u00f3digo de uma biblioteca n\u00e3o instalada (porque foi declarado como sendo necess\u00e1rio apenas para desenvolvimento).<\/p>\n<p>Por exemplo, a classe <a href=\"https:\/\/github.com\/symfony\/symfony\/blob\/8f03a1f\/src\/Symfony\/Component\/Cache\/Messenger\/EarlyExpirationHandler.php\"><code>EarlyExpirationHandler<\/code><\/a> do componente Cache da Symfony implementa interface <a href=\"https:\/\/github.com\/symfony\/symfony\/blob\/191cb52\/src\/Symfony\/Component\/Messenger\/Handler\/MessageHandlerInterface.php\"><code>MessageHandlerInterface<\/code><\/a> do componente Messenger:<\/p>\n<pre><code class=\"language-php\">class EarlyExpirationHandler implements MessageHandlerInterface\n{\n    \/\/...\n}\n<\/code><\/pre>\n<p>No entanto, <code>symfony\/cache<\/code> declara <code>symfony\/messenger<\/code> como uma <a href=\"https:\/\/github.com\/symfony\/symfony\/blob\/6fe82d8\/src\/Symfony\/Component\/Cache\/composer.json#L43\" target=\"_blank\" rel=\"noopener noreferrer\">depend\u00eancia para o desenvolvimento<\/a>. Ent\u00e3o, ao executar o Rector em um projeto que depende de <code>symfony\/cache<\/code>, ele ir\u00e1 lan\u00e7ar um erro:<\/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\".   \n<\/code><\/pre>\n<p>H\u00e1 tr\u00eas solu\u00e7\u00f5es para esta quest\u00e3o:<\/p>\n<ol>\n<li>Na configura\u00e7\u00e3o do Rector, pular o processamento do arquivo que faz refer\u00eancia \u00e0quele peda\u00e7o de c\u00f3digo:<\/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>Fa\u00e7a o download da biblioteca que falta e adicione seu caminho para ser carregado automaticamente pelo 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>Fa\u00e7a seu projeto depender da biblioteca que falta para a produ\u00e7\u00e3o:<\/li>\n<\/ol>\n<pre><code class=\"language-bash\">composer require symfony\/messenger\n<\/code><\/pre>\n<h2>Transpila\u00e7\u00e3o e integra\u00e7\u00e3o cont\u00ednua (CI)<\/h2>\n<p>Como mencionado anteriormente, em nossos computadores de desenvolvimento n\u00f3s devemos usar a flag <code>--dry-run<\/code> ao rodar o Rector, ou ent\u00e3o, o c\u00f3digo fonte ser\u00e1 substitu\u00eddo pelo c\u00f3digo transpilado. Por esta raz\u00e3o, \u00e9 mais adequado executar o processo de transpila\u00e7\u00e3o real durante a integra\u00e7\u00e3o cont\u00ednua (CI &#8211; Continuous Integration), onde podemos rodar os runners tempor\u00e1rios para executar o processo.<\/p>\n<p>Um momento ideal para executar o processo de transpila\u00e7\u00e3o \u00e9 quando se gera a libera\u00e7\u00e3o para o nosso projeto. Por exemplo, o <a href=\"https:\/\/github.com\/GraphQLAPI\/graphql-api-for-wp\/blob\/3f9fd52ddf318b9fbb33653de8acfec8dc4b4665\/.github\/workflows\/main.yml\" target=\"_blank\" rel=\"noopener noreferrer\">c\u00f3digo abaixo<\/a> \u00e9 um workflow para o <a href=\"https:\/\/github.com\/features\/actions\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub Actions<\/a>, que cria o lan\u00e7amento de um 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 }}\n<\/code><\/pre>\n<p>Este fluxo de trabalho cont\u00e9m um procedimento padr\u00e3o para <a href=\"https:\/\/leoloso.com\/posts\/github-action-to-release-wp-plugin\/\" target=\"_blank\" rel=\"noopener noreferrer\">liberar um plugin WordPress via GitHub Actions<\/a>. A nova adi\u00e7\u00e3o, para transpor o c\u00f3digo do plugin do PHP 7.4 para o 7.1, acontece nesta etapa:<\/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>Em conjunto, este fluxo de trabalho agora executa os seguintes passos:<\/p>\n<ol>\n<li>Verifica o c\u00f3digo fonte para um plugin WordPress a partir do seu reposit\u00f3rio, escrito com PHP 7.4<\/li>\n<li>Instala suas depend\u00eancias do Composer<\/li>\n<li>Transpila seu c\u00f3digo do PHP 7.4 para o 7.1<\/li>\n<li>Modifica a entrada &#8220;Requires PHP&#8221; no cabe\u00e7alho do arquivo principal do plugin do <code>\"7.4\"<\/code> para <code>\"7.1\"<\/code><\/li>\n<li>Remove as depend\u00eancias necess\u00e1rias para o desenvolvimento<\/li>\n<li>Cria o arquivo .zip do plugin, excluindo todos os arquivos desnecess\u00e1rios<\/li>\n<li>Carrega o arquivo .zip como um ativo de lan\u00e7amento (e, al\u00e9m disso, como um artefato para a A\u00e7\u00e3o GitHub)<\/li>\n<\/ol>\n<h2>Testando o c\u00f3digo transpilado<\/h2>\n<p>Uma vez que o c\u00f3digo foi transpilado para o PHP 7.1, como sabemos que ele funciona bem? Ou, em outras palavras, como sabemos que ele foi completamente convertido, e que nenhum remanescente de vers\u00f5es superiores do c\u00f3digo PHP foi deixado para tr\u00e1s?<\/p>\n<p>Semelhante \u00e0 transpila\u00e7\u00e3o do c\u00f3digo, n\u00f3s podemos implementar a solu\u00e7\u00e3o dentro de um processo CI. A id\u00e9ia \u00e9 configurar o ambiente do runner com PHP 7.1 e executar um linter sobre o c\u00f3digo transpilado. Se qualquer peda\u00e7o de c\u00f3digo n\u00e3o for compat\u00edvel com o PHP 7.1 (como uma propriedade digitada do PHP 7.4 que n\u00e3o foi convertida), ent\u00e3o o linter ir\u00e1 lan\u00e7ar um erro.<\/p>\n<p>Um linter para PHP que funciona bem \u00e9 o <a href=\"https:\/\/github.com\/php-parallel-lint\/PHP-Parallel-Lint\" target=\"_blank\" rel=\"noopener noreferrer\">PHP Parallel Lint<\/a>. N\u00f3s podemos instalar esta biblioteca como uma depend\u00eancia para desenvolvimento em nosso projeto, ou fazer com que o processo de CI a instale como um projeto aut\u00f4nomo do Composer:<\/p>\n<pre><code class=\"language-bash\">composer create-project php-parallel-lint\/php-parallel-lint\n<\/code><\/pre>\n<p>Sempre que o c\u00f3digo contiver PHP 7.2 e superior, o PHP Parallel Lint ir\u00e1 lan\u00e7ar um erro como <a href=\"https:\/\/github.com\/leoloso\/PoP\/runs\/2751846434?check_suite_focus=true\" target=\"_blank\" rel=\"noopener noreferrer\">este<\/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 %)\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>Vamos adicionar o linter ao fluxo de trabalho do nosso CI. Os passos a serem executados para transpor o c\u00f3digo do PHP 8.0 para 7.1 e test\u00e1-lo s\u00e3o:<\/p>\n<ol>\n<li>Confira o c\u00f3digo fonte<\/li>\n<li>Tenha o ambiente rodando PHP 8.0, para que o Rector possa interpretar o c\u00f3digo fonte<\/li>\n<li>Transpile o c\u00f3digo para o PHP 7.1<\/li>\n<li>Instale a ferramenta linter do PHP<\/li>\n<li>Mude a vers\u00e3o do ambiente PHP para 7.1<\/li>\n<li>Executar o linter no c\u00f3digo transpilado<\/li>\n<\/ol>\n<p>Este <a href=\"https:\/\/github.com\/leoloso\/PoP\/blob\/b93d3e35cb59e0281b45899fd82231c3d8cbbe25\/.github\/workflows\/downgrade_php_tests.yml\" target=\"_blank\" rel=\"noopener noreferrer\">fluxo de trabalho da GitHub Action<\/a> faz o trabalho:<\/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>Por favor note que v\u00e1rios arquivos <code>bootstrap80.php<\/code> das bibliotecas polifill da Symfony (que n\u00e3o precisam ser transpilados) devem ser exclu\u00eddos do linter. Estes arquivos cont\u00eam PHP 8.0, ent\u00e3o o linter lan\u00e7aria erros ao process\u00e1-los. Entretanto, excluir estes arquivos \u00e9 seguro, uma vez que eles ser\u00e3o carregados na produ\u00e7\u00e3o somente quando <a href=\"https:\/\/github.com\/symfony\/polyfill-mbstring\/blob\/9ad2f3c\/bootstrap.php#L14-L16\" target=\"_blank\" rel=\"noopener noreferrer\">rodando o PHP 8.0 ou superior<\/a>:<\/p>\n<pre><code class=\"language-php\">if (\\PHP_VERSION_ID &gt;= 80000) {\n  return require __DIR__.'\/bootstrap80.php';\n}\n<\/code><\/pre>\n\n<h2>Resumo<\/h2>\n<p>Este artigo nos ensinou como transpilar nosso c\u00f3digo PHP, permitindo-nos usar PHP 8.0 no c\u00f3digo fonte e criar uma vers\u00e3o que funcione no PHP 7.1. A transpila\u00e7\u00e3o \u00e9 feita atrav\u00e9s do <a href=\"https:\/\/github.com\/rectorphp\/rector\" target=\"_blank\" rel=\"noopener noreferrer\">Rector<\/a>, uma ferramenta reconstrutora do PHP.<\/p>\n<p>Transpilar nosso c\u00f3digo nos torna melhores desenvolvedores, uma vez que podemos capturar melhor os bugs no desenvolvimento e produzir c\u00f3digo que \u00e9 naturalmente mais f\u00e1cil de ler e entender.<\/p>\n<p>A transpila\u00e7\u00e3o tamb\u00e9m nos permite desacoplar nosso c\u00f3digo com requisitos espec\u00edficos de PHP do CMS. Agora n\u00f3s podemos fazer isso se quisermos usar a \u00faltima vers\u00e3o do PHP para criar um plugin WordPress ou m\u00f3dulo Drupal dispon\u00edvel publicamente sem restringir severamente nossa base de usu\u00e1rios.<\/p>\n<p><em>Voc\u00ea ainda tem alguma pergunta sobre a transpila\u00e7\u00e3o do PHP? Nos informe na se\u00e7\u00e3o de coment\u00e1rios!<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Em circunst\u00e2ncias ideais, n\u00f3s devemos usar o PHP 8.0 (a \u00faltima vers\u00e3o a partir do momento em que escrevemos este artigo) para todos os nossos sites &#8230;<\/p>\n","protected":false},"author":196,"featured_media":44397,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kinsta_gated_content":false,"_kinsta_gated_content_redirect":"","footnotes":""},"tags":[32,270],"topic":[985,997],"class_list":["post-44394","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-php","tag-programming","topic-aprenda-php","topic-funcoes-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>O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP<\/title>\n<meta name=\"description\" content=\"Cansado de trabalhar com v\u00e1rias vers\u00f5es PHP? Aprenda como escrever c\u00f3digo fonte com PHP 8.0, e transpilar para vers\u00f5es anteriores no 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\/pt\/blog\/transpilacao-php\/\" \/>\n<meta property=\"og:locale\" content=\"pt_PT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP\" \/>\n<meta property=\"og:description\" content=\"Cansado de trabalhar com v\u00e1rias vers\u00f5es PHP? Aprenda como escrever c\u00f3digo fonte com PHP 8.0, e transpilar para vers\u00f5es anteriores no PHP.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/\" \/>\n<meta property=\"og:site_name\" content=\"Kinsta\u00ae\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/kinstapt\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-30T14:04:51+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-08-22T07:45:45+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg\" \/>\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=\"Cansado de trabalhar com v\u00e1rias vers\u00f5es PHP? Aprenda como escrever c\u00f3digo fonte com PHP 8.0, e transpilar para vers\u00f5es anteriores no PHP.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg\" \/>\n<meta name=\"twitter:creator\" content=\"@losoviz\" \/>\n<meta name=\"twitter:site\" content=\"@kinsta_pt\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Leonardo Losoviz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tempo estimado de leitura\" \/>\n\t<meta name=\"twitter:data2\" content=\"23 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/\"},\"author\":{\"name\":\"Leonardo Losoviz\",\"@id\":\"https:\/\/kinsta.com\/pt\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238\"},\"headline\":\"O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP\",\"datePublished\":\"2021-09-30T14:04:51+00:00\",\"dateModified\":\"2023-08-22T07:45:45+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/\"},\"wordCount\":4466,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/pt\/#organization\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg\",\"keywords\":[\"php\",\"programming\"],\"inLanguage\":\"pt-PT\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/\",\"url\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/\",\"name\":\"O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/pt\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg\",\"datePublished\":\"2021-09-30T14:04:51+00:00\",\"dateModified\":\"2023-08-22T07:45:45+00:00\",\"description\":\"Cansado de trabalhar com v\u00e1rias vers\u00f5es PHP? Aprenda como escrever c\u00f3digo fonte com PHP 8.0, e transpilar para vers\u00f5es anteriores no PHP.\",\"breadcrumb\":{\"@id\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#breadcrumb\"},\"inLanguage\":\"pt-PT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-PT\",\"@id\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#primaryimage\",\"url\":\"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg\",\"width\":1460,\"height\":730,\"caption\":\"O Guia Supremo para Transporta\u00e7\u00e3o de C\u00f3digo PHP\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kinsta.com\/pt\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Aprenda PHP\",\"item\":\"https:\/\/kinsta.com\/pt\/topicos\/aprenda-php\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kinsta.com\/pt\/#website\",\"url\":\"https:\/\/kinsta.com\/pt\/\",\"name\":\"Kinsta\u00ae\",\"description\":\"Solu\u00e7\u00f5es de hospedagem Premium, r\u00e1pida e segura\",\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/pt\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kinsta.com\/pt\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pt-PT\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/kinsta.com\/pt\/#organization\",\"name\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/pt\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-PT\",\"@id\":\"https:\/\/kinsta.com\/pt\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2023\/12\/kinsta-logo.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2023\/12\/kinsta-logo.jpeg\",\"width\":500,\"height\":500,\"caption\":\"Kinsta\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/pt\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/kinstapt\/\",\"https:\/\/x.com\/kinsta_pt\",\"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\/pt\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238\",\"name\":\"Leonardo Losoviz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-PT\",\"@id\":\"https:\/\/kinsta.com\/pt\/#\/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\/pt\/blog\/author\/leonardolosoviz\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP","description":"Cansado de trabalhar com v\u00e1rias vers\u00f5es PHP? Aprenda como escrever c\u00f3digo fonte com PHP 8.0, e transpilar para vers\u00f5es anteriores no 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\/pt\/blog\/transpilacao-php\/","og_locale":"pt_PT","og_type":"article","og_title":"O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP","og_description":"Cansado de trabalhar com v\u00e1rias vers\u00f5es PHP? Aprenda como escrever c\u00f3digo fonte com PHP 8.0, e transpilar para vers\u00f5es anteriores no PHP.","og_url":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/","og_site_name":"Kinsta\u00ae","article_publisher":"https:\/\/www.facebook.com\/kinstapt\/","article_published_time":"2021-09-30T14:04:51+00:00","article_modified_time":"2023-08-22T07:45:45+00:00","og_image":[{"width":1460,"height":730,"url":"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg","type":"image\/jpeg"}],"author":"Leonardo Losoviz","twitter_card":"summary_large_image","twitter_description":"Cansado de trabalhar com v\u00e1rias vers\u00f5es PHP? Aprenda como escrever c\u00f3digo fonte com PHP 8.0, e transpilar para vers\u00f5es anteriores no PHP.","twitter_image":"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg","twitter_creator":"@losoviz","twitter_site":"@kinsta_pt","twitter_misc":{"Escrito por":"Leonardo Losoviz","Tempo estimado de leitura":"23 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#article","isPartOf":{"@id":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/"},"author":{"name":"Leonardo Losoviz","@id":"https:\/\/kinsta.com\/pt\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238"},"headline":"O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP","datePublished":"2021-09-30T14:04:51+00:00","dateModified":"2023-08-22T07:45:45+00:00","mainEntityOfPage":{"@id":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/"},"wordCount":4466,"commentCount":0,"publisher":{"@id":"https:\/\/kinsta.com\/pt\/#organization"},"image":{"@id":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg","keywords":["php","programming"],"inLanguage":"pt-PT","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/","url":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/","name":"O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP","isPartOf":{"@id":"https:\/\/kinsta.com\/pt\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#primaryimage"},"image":{"@id":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg","datePublished":"2021-09-30T14:04:51+00:00","dateModified":"2023-08-22T07:45:45+00:00","description":"Cansado de trabalhar com v\u00e1rias vers\u00f5es PHP? Aprenda como escrever c\u00f3digo fonte com PHP 8.0, e transpilar para vers\u00f5es anteriores no PHP.","breadcrumb":{"@id":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#breadcrumb"},"inLanguage":"pt-PT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/"]}]},{"@type":"ImageObject","inLanguage":"pt-PT","@id":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#primaryimage","url":"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg","contentUrl":"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2021\/09\/transpiling-php.jpeg","width":1460,"height":730,"caption":"O Guia Supremo para Transporta\u00e7\u00e3o de C\u00f3digo PHP"},{"@type":"BreadcrumbList","@id":"https:\/\/kinsta.com\/pt\/blog\/transpilacao-php\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kinsta.com\/pt\/"},{"@type":"ListItem","position":2,"name":"Aprenda PHP","item":"https:\/\/kinsta.com\/pt\/topicos\/aprenda-php\/"},{"@type":"ListItem","position":3,"name":"O Guia Definitivo para a Transpila\u00e7\u00e3o do C\u00f3digo PHP"}]},{"@type":"WebSite","@id":"https:\/\/kinsta.com\/pt\/#website","url":"https:\/\/kinsta.com\/pt\/","name":"Kinsta\u00ae","description":"Solu\u00e7\u00f5es de hospedagem Premium, r\u00e1pida e segura","publisher":{"@id":"https:\/\/kinsta.com\/pt\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kinsta.com\/pt\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pt-PT"},{"@type":"Organization","@id":"https:\/\/kinsta.com\/pt\/#organization","name":"Kinsta","url":"https:\/\/kinsta.com\/pt\/","logo":{"@type":"ImageObject","inLanguage":"pt-PT","@id":"https:\/\/kinsta.com\/pt\/#\/schema\/logo\/image\/","url":"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2023\/12\/kinsta-logo.jpeg","contentUrl":"https:\/\/kinsta.com\/pt\/wp-content\/uploads\/sites\/3\/2023\/12\/kinsta-logo.jpeg","width":500,"height":500,"caption":"Kinsta"},"image":{"@id":"https:\/\/kinsta.com\/pt\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/kinstapt\/","https:\/\/x.com\/kinsta_pt","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\/pt\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238","name":"Leonardo Losoviz","image":{"@type":"ImageObject","inLanguage":"pt-PT","@id":"https:\/\/kinsta.com\/pt\/#\/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\/pt\/blog\/author\/leonardolosoviz\/"}]}},"acf":[],"_links":{"self":[{"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/posts\/44394","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/users\/196"}],"replies":[{"embeddable":true,"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/comments?post=44394"}],"version-history":[{"count":7,"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/posts\/44394\/revisions"}],"predecessor-version":[{"id":44446,"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/posts\/44394\/revisions\/44446"}],"alternate":[{"embeddable":true,"hreflang":"en","title":"English","href":"https:\/\/kinsta.com\/pt\/wp-json\/kinsta\/v1\/posts\/44394\/translations\/en"},{"embeddable":true,"hreflang":"es","title":"Spanish","href":"https:\/\/kinsta.com\/pt\/wp-json\/kinsta\/v1\/posts\/44394\/translations\/es"},{"embeddable":true,"hreflang":"it","title":"Italian","href":"https:\/\/kinsta.com\/pt\/wp-json\/kinsta\/v1\/posts\/44394\/translations\/it"},{"embeddable":true,"hreflang":"fr","title":"French","href":"https:\/\/kinsta.com\/pt\/wp-json\/kinsta\/v1\/posts\/44394\/translations\/fr"},{"embeddable":true,"hreflang":"pt","title":"Portuguese","href":"https:\/\/kinsta.com\/pt\/wp-json\/kinsta\/v1\/posts\/44394\/translations\/pt"},{"embeddable":true,"hreflang":"de","title":"German","href":"https:\/\/kinsta.com\/pt\/wp-json\/kinsta\/v1\/posts\/44394\/translations\/de"},{"embeddable":true,"hreflang":"nl","title":"Dutch","href":"https:\/\/kinsta.com\/pt\/wp-json\/kinsta\/v1\/posts\/44394\/translations\/nl"},{"href":"https:\/\/kinsta.com\/pt\/wp-json\/kinsta\/v1\/posts\/44394\/tree"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/media\/44397"}],"wp:attachment":[{"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/media?parent=44394"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/tags?post=44394"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/kinsta.com\/pt\/wp-json\/wp\/v2\/topic?post=44394"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}