PHP 7.4, a próxima versão menor do PHP 7, foi lançada em 28 de novembro de 2019. Então é hora de mergulharmos em algumas das mais emocionantes adições e novas funcionalidades que terão tornado o PHP mais rápido e confiável.

Atualização: PHP 8.1 (versão oficial) está agora disponível para todos os clientes Kinsta. O PHP 7.4 não é mais suportado na Kinsta. Por favor, note que somente suportamos versões PHP 8.0, 8.1, 8.2 e 8.3.

Mesmo que o PHP 7.4 aumente significativamente a performance e melhore a legibilidade do código, o PHP 8 será o verdadeiro marco para a performance do PHP, já que a proposta de inclusão do JIT já foi aprovada.

De qualquer forma, hoje estamos passando por algumas das funcionalidades e mudanças mais interessantes que estamos esperando com o PHP 7.4. Só para que conste, estas foram as datas importantes para a versão 7.4:

  • 6 de Junho de 2019: PHP 7.4 Alpha 1
  • 18 de Julho de 2019: PHP 7.4 Beta 1 – Congelamento de recursos
  • 28 de Novembro de 2019: Lançamento do PHP 7.4 GA

Você pode conferir a lista completa de recursos e adições na página oficial da RFC.

O que há de novo no PHP 7.4?

Neste artigo estamos cobrindo várias mudanças e funcionalidades que devem ser adicionadas à linguagem com o lançamento final do PHP 7.4:

Esqueça o array_merge: PHP 7.4 traz o operador de propagação para a expressão array

Disponível desde o PHP 5.6, a descompactação de argumentos é uma sintaxe para descompactar arrays e Traversables em listas de argumentos. Para descompactar um array ou um Traversable, ele deve ser precedido por … (3 pontos), como mostrado no exemplo a seguir:

function test(...$args) { var_dump($args); }
test(1, 2, 3);

Agora esta RFC do PHP 7.4 propõe estender este recurso para definições de array:

$arr = [...$args];

O primeiro benefício declarado do Spread Operator na expressão de array é tudo sobre desempenho. Na verdade, o médico da RFC afirma:

O operador Spread deve ter melhor desempenho do que o array_merge. Isso não é só porque o operador spread é uma estrutura de linguagem enquanto array_merge é uma função, mas também porque a otimização de tempo de compilação pode ser performante para arrays constantes.

Uma vantagem significativa do operador Spread é que ele suporta qualquer objeto passível de ser atravessado, enquanto a função array_merge apenas suporta arrays.

Aqui está um exemplo de descompactação de argumentos na expressão array:

$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
var_dump($fruits);

Se você executar este código com o PHP 7.3 ou anterior, o PHP emite um erro de Parse:

Parse error: syntax error, unexpected '...' (T_ELLIPSIS), expecting ']' in /app/spread-operator.php on line 3

Em vez disso, o PHP 7.4 retornaria um array:

array(5) {
	[0]=>
	string(6) "banana"
	[1]=>
	string(6) "orange"
	[2]=>
	string(5) "apple"
	[3]=>
	string(4) "pear"
	[4]=>
	string(10) "watermelon"
}

A RFC afirma que podemos expandir o mesmo array várias vezes. Além disso, podemos usar a sintaxe Spread Operator em qualquer lugar do array, já que elementos normais podem ser adicionados antes ou depois do operador spread. Assim, o seguinte código funcionará como seria de esperar:

$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$arr3 = [...$arr1, ...$arr2];
$arr4 = [...$arr1, ...$arr3, 7, 8, 9];

Também é possível desempacotar arrays retornados por uma função diretamente em um novo array:

function buildArray(){
	return ['red', 'green', 'blue'];
}
$arr1 = [...buildArray(), 'pink', 'violet', 'yellow'];

O PHP 7.4 produz o seguinte array:

array(6) {
	[0]=>
	string(3) "red"
	[1]=>
	string(5) "green"
	[2]=>
	string(4) "blue"
	[3]=>
	string(4) "pink"
	[4]=>
	string(6) "violet"
	[5]=>
	string(6) "yellow"
}

Também podemos usar a sintaxe do gerador:

function generator() {
	for ($i = 3; $i <= 5; $i++) {
		yield $i;
	}
}
$arr1 = [0, 1, 2, ...generator()];

Mas não nos é permitido desempacotar arrays passados por arrays. Considere o seguinte exemplo:

$arr1 = ['red', 'green', 'blue'];
$arr2 = [...&$arr1];

Se tentarmos descompactar um array por referência, o PHP lança o seguinte erro de Parse:

Parse error: syntax error, unexpected '&' in /app/spread-operator.php on line 3

De qualquer forma, se os elementos do primeiro array são armazenados por referência, eles são armazenados por referência no segundo array, também. Aqui está um exemplo:

$arr0 = 'red';
$arr1 = [&$arr0, 'green', 'blue'];
$arr2 = ['white', ...$arr1, 'black'];

E aqui está o que temos com o PHP 7.4:

array(5) {
	[0]=>
	string(5) "white"
	[1]=>
	&string(3) "red"
	[2]=>
	string(5) "green"
	[3]=>
	string(4) "blue"
	[4]=>
	string(5) "black"
}

A proposta do operador de Spread passou com 43 para 1 votos.

Arrow Functions 2.0 (Short Closures)

No PHP, funções anônimas são consideradas bastante verbosas e difíceis de implementar e manter. Esta RFC propõe a introdução da sintaxe mais curta e clara das Arrow Functions (ou Short Closures), que deve nos permitir limpar significativamente nosso código PHP.

Considere o seguinte exemplo:

function cube($n){
	return ($n * $n * $n);
}
$a = [1, 2, 3, 4, 5];
$b = array_map('cube', $a);
print_r($b);

O PHP 7.4 permite usar uma sintaxe mais concisa, e a função acima pode ser reescrita da seguinte forma:

$a = [1, 2, 3, 4, 5];
$b = array_map(fn($n) => $n * $n * $n, $a);
print_r($b);

Atualmente, funções anônimas (closures) podem herdar variáveis definidas no escopo pai graças à construção da linguagem de use, como mostrado abaixo:

$factor = 10;
$calc = function($num) use($factor){
	return $num * $factor;
};

Mas com o PHP 7.4, variáveis definidas no escopo pai são implicitamente capturadas pelo valor (ligação implícita por valor ao escopo). Assim podemos escrever toda a função vista acima numa única linha:

$factor = 10;
$calc = fn($num) => $num * $factor;

A variável definida no escopo pai pode ser usada na função de seta exatamente como se estivéssemos usando use($var), e não é possível modificar uma variável do escopo pai.

A nova sintaxe é uma grande melhoria para a linguagem, pois permite-nos construir código mais legível e de fácil manutenção. Também podemos usar tipos de parâmetros e retornos, valores padrão, listas de argumentos de comprimento variável (variadic functions), podemos passar e retornar por referência, etc. Finalmente, Short Closures também podem ser usados em métodos de classe, e eles podem fazer uso da variável $this como fechamentos regulares.

Esta RFC foi aprovada com 51 a 8 votos, então podemos esperar que ela faça parte das adições do PHP 7.4.

Operador de coalescência nula

Adicionado com PHP 7, o operador coalescente (??? ) é útil quando precisamos usar um operador ternário em conjunto com isset(). Retorna o primeiro operando se existe e não é NULL. Caso contrário, retorna o segundo operando. Aqui está um exemplo:

$username = $_GET['user'] ?? 'nobody';

O que esse código faz é bem simples: ele obtém o parâmetro request e define um valor padrão se ele não existir. O significado dessa linha é claro, mas e se tivéssemos nomes de variáveis muito mais longos como neste exemplo da RFC?

$this->request->data['comments']['user_id'] = $this->request->data['comments']['user_id'] ?? 'value';

A longo prazo, este código pode ser um pouco difícil de manter. Assim, com o objetivo de ajudar os desenvolvedores a escrever código mais intuitivo, esta RFC propõe a introdução do operador de coalescência nula (??=). Então, em vez de escrever o código anterior, poderíamos escrever o seguinte:

$this->request->data['comments']['user_id'] ??= 'value';

Se o valor do parâmetro esquerdo for null, então o valor do parâmetro direito é utilizado.
Note que, enquanto o operador coalescente é um operador de comparação, ??= é um operador de atribuição.

Esta proposta foi aprovada com 37 votos a favor e 4 contra.

Typed Properties 2.0

As declarações de tipo de argumento, ou dicas de tipo, permitem especificar o tipo de uma variável que se espera que seja passada para uma função ou um método de classe. Dicas de tipo são um recurso disponível desde o PHP 5, e desde o PHP 7.2 podemos usá-las com o tipo de dados do object. Agora o PHP 7.4 traz o type hinting um passo à frente adicionando suporte para declarações de tipo de propriedade de primeira classe. Aqui está um exemplo muito básico:

class User {
	public int $id;
	public string $name;
}

Todos os tipos são suportados, com exceção de void e callable:

public int $scalarType;
protected ClassName $classType;
private ?ClassName $nullableClassType;

A RFC explica o motivo pelo qual não há suporte para void e callable:

O tipo de vazio não é suportado, porque não é útil e tem semântica pouco clara.

O tipo de chamada não é suportado, porque seu comportamento é dependente do contexto.

Assim podemos usar com segurança bool, int, float, string, array, object, iterable, self, parent, qualquer classe ou nome de interface, e tiposanuláveis (? type).

Os tipos podem ser usados em propriedades estáticas:

public static iterable $staticProp;

Também são permitidos com a notação var:

var bool $flag;

É possível definir valores de propriedade padrão, que obviamente devem corresponder ao tipo de propriedade declarado, mas somente propriedades anuláveis podem ter um valor null padrão:

public string $str = "foo";
public ?string $nullableStr = null;

O mesmo tipo aplica-se a todas as propriedades numa única declaração:

public float $x, $y;

O que acontece se fizermos um erro no tipo de propriedade? Considere o seguinte código:

class User {
	public int $id;
	public string $name;
}

$user = new User;
$user->id = 10;
$user->name = [];

No código acima, declaramos um tipo de propriedade string, mas definimos um array como valor de propriedade. Neste cenário, obtemos o seguinte erro Fatal:

Fatal error: Uncaught TypeError: Typed property User::$name must be string, array used in /app/types.php:9

Esta RFC foi aprovada com 70 votos a 1 voto.

Weak References

Com essa RFC, o PHP 7.4 introduz a classe WeakReference, que permite aos programadores manter uma referência a um objeto que não impede que o próprio objeto seja destruído.

Atualmente o PHP suporta referências fracas usando uma extensão como pecl-weakref. De qualquer forma, a nova API é diferente da classe WeakRef documentada.

Aqui está um exemplo do autor desta proposta, Nikita Popov:

$object = new stdClass;
$weakRef = WeakReference::create($object);

var_dump($weakRef->get());
unset($object);
var_dump($weakRef->get());

O primeiro var_dump imprime object(stdClass)#1 (0) {}, enquanto o segundo var_dump imprime NULL, pois o objeto referenciado foi destruído.

Esta RFC passou com 28 a 5 votos.

Tipos de retorno covariantes e parâmetros contraservariantes

A variância é uma propriedade das hierarquias de classes que descrevem como os tipos de um construtor de tipo afetam os subtipos. Em geral, um construtor de tipo pode ser:

  • Invariante: se o tipo da restrição de supertipo for o tipo do subtipo.
  • Covariante: se a ordenação dos tipos é preservada (os tipos são ordenados de mais específico para mais genérico).
  • Contravariante: se inverter a ordem (os tipos são ordenados de mais genéricos para mais específicos).

Atualmente, o PHP tem parâmetros e tipos de retorno invariantes, com poucas exceções. Esta RFC propõe permitir covariância e contravariância em tipos de parâmetros e tipos de retorno, fornecendo também vários exemplos de código.

Aqui está um exemplo de tipo de retorno covariante:

interface Factory {
	function make(): object;
}

class UserFactory implements Factory {
	function make(): User;
}

E aqui está um exemplo de tipo de parâmetro contravariante:

interface Concatable {
	function concat(Iterator $input); 
}
 
class Collection implements Concatable {
	// accepts all iterables, not just Iterator
	function concat(iterable $input) {/* . . . */}
}

Veja a RFC para um olhar mais atento sobre covariância e contravariação no PHP 7.4.

Esta RFC passou com 39 para 1 votos.

Preloading

Esta proposta de Dmitry Stogov é uma das nossas favoritas porque deve trazer um impulso significativo no desempenho. Preloading é o processo de carregar bibliotecas e frameworks para o OPCache na inicialização do módulo (leia mais sobre o ciclo de vida do PHP).

Ciclo de vida do PHP
Ciclo de vida do PHP (Fonte da imagem: PHP Internals)

Aqui está como o preloading funciona nas palavras de Dmitry:

Na inicialização do servidor – antes que qualquer código de aplicação seja executado – podemos carregar um certo conjunto de arquivos PHP na memória – e tornar seu conteúdo “permanentemente disponível” para todas as requisições subseqüentes que serão atendidas por esse servidor. Todas as funções e classes definidas nestes arquivos estarão disponíveis para solicitações fora da caixa, exatamente como entidades internas.

Esses arquivos são carregados na inicialização do servidor, são executados antes de qualquer aplicação e permanecem disponíveis para quaisquer solicitações futuras. Isso é óptimo em termos de desempenho.

O Preloading é controlada por uma diretiva php.ini específica: opcache.preload. Esta diretiva especifica um script PHP para ser compilado e executado na inicialização do servidor. Este arquivo pode ser usado para pré-carregar arquivos adicionais, incluindo-os ou através da função opcache_compile_file() (leia mais na documentação do PHP).

Mas há uma desvantagem. Na verdade, a RFC afirma explicitamente:

Os arquivos Preloading permanecem em cache na memória opcache para sempre. A modificação de seus arquivos fonte correspondentes não terá nenhum efeito sem que outro servidor seja reiniciado.

No entanto, todas as funções definidas em arquivos Preloading serão permanentemente carregadas nas tabelas de funções e classes do PHP, e permanecerão disponíveis para cada solicitação futura. Isto conduzirá a melhorias de bom desempenho, ainda que essas melhorias possam ser consideravelmente variáveis.

Você pode ler mais sobre as limitações e exceções de pré-carregamento na página oficial Pré-carregamento RFC.

Novo mecanismo para a serialização de objetos personalizados

Esta é outra proposta de Nikita Popov aprovada por uma grande maioria de votos.

Atualmente, temos dois mecanismos diferentes para serialização personalizada de objetos em PHP:

  • Os métodos __sleep() e __wakeup() mágicos
  • A interface serializável

De acordo com Nikita, ambas as opções têm problemas que levam a um código complexo e não confiável. Você pode mergulhar fundo neste tópico na RFC. Aqui eu apenas menciono que o novo mecanismo de serialização deve evitar esses problemas, fornecendo dois novos métodos mágicos, __serialize() e __unserialize(), que combinam os dois mecanismos existentes.

Esta proposta foi aprovada por 20 a 7 votos a favor.

Depreciações

As seguintes funções/funcionalidades serão obsoletas com o PHP 7.4. Para uma lista mais abrangente de depreciações, confira as Notas de Atualização do PHP 7.4.

Alterar a prioridade do operador da concatenação

Atualmente, em PHP os operadores aritméticos “+” e “-“, e o operador de string “.” são associativos à esquerda e têm a mesma precedência (leia mais sobre Precedência do Operador).

Como exemplo, considere a seguinte linha:

echo "sum: " . $a + $b;

No PHP 7.3 este código produz o seguinte aviso:

Warning: A non-numeric value encountered in /app/types.php on line 4

Isto porque a concatenação é avaliada da esquerda para a direita. É o mesmo que escrever o seguinte código:

echo ("sum: " . $a) + $b;

Esta RFC propõe alterar a precedência dos operadores, dando a “.” uma precedência inferior à dos operadores “+” e “-“, para que as adições e subtracções sejam sempre efectuadas antes da concatenação da string. Essa linha de código deve ser equivalente ao seguinte:

echo "sum: " . ($a + $b);

Esta é uma proposta em duas etapas:

  • A partir da versão 7.4, o PHP deve emitir um aviso de obsolescência quando encontrar uma expressão não incluída entre parênteses com “+”, “-” e “.
  • A mudança real de precedência destes operadores deve ser adicionada com o PHP 8.

Ambas as propostas foram aprovadas por larga maioria de votos.

Depreciar operador ternário associativo-esquerdo

No PHP o operador ternário, ao contrário de muitas outras linguagens, é deixado-associativo. De acordo com Nikita Popof, isso pode ser confuso para programadores que alternam entre diferentes linguagens.

Atualmente, em PHP o seguinte código está correto:

$b = $a == 1 ? 'one' : $a == 2 ? 'two' : $a == 3 ? 'three' : 'other';

É interpretado como:

$b = (($a == 1 ? 'one' : $a == 2) ? 'two' : $a == 3) ? 'three' : 'other';

E isso pode levar a erros, porque pode não ser o que pretendemos fazer. Assim, esta RFC propõe depreciar e remover o uso da associatividade esquerda para operadores ternários e forçar os desenvolvedores a usar parênteses.

Esta é outra proposta de duas etapas:

  • A partir do PHP 7.4, os operadores ternários aninhados sem o uso explícito de parênteses geram um aviso de depreciação..
  • A partir do PHP 8.0, haverá um erro de execução de compilação.

Esta proposta foi aprovada com 35 a 10 votos a favor.

O que o PHP 7.4 significa para usuários do WordPress?

O PHP é a linguagem de programação do lado do servidor mais usada na web. De acordo com a W3Techs, em 2 de dezembro de 2019, o uso do PHP é usado por 78,9% de todos os sites cuja linguagem de programação do lado do servidor eles podem detectar.

Utilização do PHP (Dezembro 2019)
Utilização do PHP (Dezembro 2019)

Infelizmente, o PHP 5 ainda é usado por 44.0% de todos os sites com uma linguagem de programação conhecida do lado do servidor. Se você adicionar o número de usuários que ainda usam o PHP 7.0 e 7.1, acontece que a grande maioria dos sites estão rodando versões não suportadas do PHP.

Versões PHP suportadas
Versões PHP suportadas (Fonte da imagem: Supported Versions)

De acordo com a página oficial Estatísticas do WordPress, a partir de agora, 64% de todos os sites do WordPress estão rodando versões não suportadas do PHP. Apenas um pouco mais de 13% estão usando a versão mais recente: PHP 7.3. E a última versão, PHP 7.4, ainda não apareceu. Você pode ver que a grande maioria dos usuários, mais de 23%, ainda estão rodando no PHP 5.6.

WordPress PHP version Stats
WordPress PHP version Stats

Recomendamos vivamente que peça ao seu host uma versão suportada do PHP, de preferência de acordo com os requisitos oficiais do WordPress. A partir desta escrita, maio de 2019, WordPress requer:

  • PHP versão 7.3 ou superior.
  • MySQL versão 5.6 ou superior OU MariaDB versão 10.1 ou superior.
  • Suporte a HTTPS

Desempenho do PHP 7

Os números acima são especialmente desencorajadores vindo de um ponto de vista de desempenho, já que o PHP 7 mostrou ser significativamente mais rápido. Aqui estão algumas estatísticas:


Nós rodamos nossos próprios benchmarks de desempenho PHP com PHP 7.3. Vimos que o WordPress 5.0 no PHP 7.3 poderia executar quase três vezes mais transações (pedidos) por segundo em comparação com o PHP 5.6. Estaremos lançando benchmarks do PHP 7.4 em breve!

Referências do WordPress 5.0 PHP
Referências do WordPress 5.0 PHP
  • WordPress 5.0 PHP 5.6 benchmark: 91,64 req/sec
  • Resultados de benchmark do WordPress 5.0 PHP 7.0: 206.71 req/sec
  • Resultados de benchmark do WordPress 5.0 PHP 7.1: 210.98 req/sec
  • Resultados de benchmark do WordPress 5.0 PHP 7.2: 229.18 req/sec
  • WordPress 5.0 PHP 7.3 resultados de benchmark: 253.20 req/sec 🏆

Muitos são lentos para atualizar simplesmente por causa do tempo envolvido com o teste de novos todos os seus plugins de terceiros e temas para garantir que eles funcionam corretamente. Mas muitas vezes, resume-se ao facto de ainda não o terem feito.

Verificando sua versão PHP

Não tem certeza de qual versão do PHP você está executando? Uma das maneiras mais fáceis de verificar é usar uma ferramenta como o Pingdom ou o Google Chrome Devtools. O primeiro cabeçalho do pedido HTTP mostrará tipicamente a versão.

Verifique a versão PHP em Pingdom
Verifique a versão PHP em Pingdom

Isso depende da máquina não modificar o valor do cabeçalho X-Powered-By. No entanto, muitos o fazem por razões de segurança (incluindo Kinsta). Se sim, você pode não ver sua versão do PHP. Nesse caso, se você estiver executando o WordPress 5.2 ou superior, há uma nova ferramenta Site Health que você pode usar. Vá até “Tools” → “Site Health” → “Info” e na seção “Server” encontrará a versão PHP do seu servidor.

Verifique a versão PHP com a ferramenta WordPress Site Health
Verifique a versão PHP com a ferramenta WordPress Site Health

Alternativamente, você pode instalar um plugin gratuito como Version Info, que mostrará algumas informações básicas do servidor no rodapé do seu painel de administração do WordPress. Algumas outras maneiras de ver sua versão do PHP incluem fazer upload de um arquivo via FTP, ou simplesmente chegar ao seu host e perguntar.

Atualizando para PHP 7.4

A versão final do PHP 7.4 está disponível agora mesmo na Kinsta. Alternativamente, você pode testar seu site WordPress localmente ou verificar seus scripts em um ambiente como o Docker, que permite que você teste diferentes versões do PHP a partir da linha de comando.

A maneira mais fácil de começar a testar é criar um ambiente de teste, pois isso se assemelhará muito ao seu site de produção ao vivo. No painel do MyKinsta, clique no seu site e mude para Ambiente de teste.

Criar ambiente de desenvolvimento do WordPress
Criar ambiente de teste do WordPress

Então, no menu “Ferramentas” mude seu mecanismo PHP para PHP 7.4 (Beta). Você pode então começar a testar para garantir a compatibilidade do seu código, plugins de terceiros e temas.

Como nas versões anteriores do PHP, nosso recurso PHP auto-regenerativo suporta totalmente o PHP 7.4. Se o PHP cair por qualquer razão, nós o reiniciamos automaticamente. Se o reinício não resolver o problema, nosso sistema de monitoramento alertará nossa equipe de administração de sistemas para investigar a causa do problema.

Alterar para PHP 7.4
Alterar para PHP 7.4

Veja detalhes sobre o lançamento do PHP 7.4 na Kinsta.

Instalando e executando o PHP 7.4 no Docker

Queres testar no Docker? Felizmente, você não precisa compilar e configurar o PHP 7.4 manualmente. Se você já tem o Docker instalado em seu sistema, você só precisa instalar o Docker Image não oficial do PHP-FPM 7.4 e executar seus testes a partir da linha de comando em poucos segundos.

 

Instalando a imagem do Nginx Docker
Instalando a imagem do Nginx Docker

Se você preferir executar seu código PHP 7.4 em seu navegador, você também precisa instalar uma imagem Nginx ou Apache. Mas não se preocupe. Basta seguir as instruções do desenvolvedor. Copie e cole os comandos da página Docker Image para a sua ferramenta de linha de comando, e você está pronto para começar.

Resumo

Neste artigo, cobrimos um bom número de mudanças e adições que podemos esperar com o lançamento do PHP 7.4. Se você está procurando a lista completa de recursos, junto com a documentação oficial da RFC, confira os seguintes recursos:

Vamos mantê-lo atualizado com todas as últimas informações sobre o PHP 7.4. Se você é um cliente Kinsta, você já pode começar a mover seus sites do WordPress para a versão mais recente.

Você está pronto para instalar e testar os próximos recursos do PHP? Qual deles é o seu favorito? Compartilhe suas idéias conosco nos comentários abaixo.

Carlo Daniele Kinsta

Carlo is a passionate lover of webdesign and front-end development. He has been playing with WordPress for more than 20 years, also in collaboration with Italian and European universities and educational institutions. He has written hundreds of articles and guides about WordPress, published both on Italian and international websites, as well as on printed magazines. You can find him on LinkedIn.