Última atualização:

Novidades do PHP 8.2 em 2022

Nawarian
Nawarian php

Novembro está chegando, e com ele grandes novidades no ecossistema PHP! O PHP 8.2 traz otimizações de performance, mudanças na sintaxe da linguagem e funções utilitárias que vão tornar o desenvolvimento com PHP ainda mais prazeiroso!

O PHP 8.2 vai ser lançado no dia 08 de Dezembro de 2022 de acordo com a documentação oficial. Mas caso você queira experimentar antes do tempo, deixo aqui uma tabelinha com as principais datas antes do lançamento oficial:

DataVersãoDetalhes
13 de Outubro de 2022Release Candidate (RC) 4Página de anúncio oficial
27 de Outubro de 2022Release Candidate (RC) 4Página de anúncio oficial
10 de Novembro de 2022Release Candidate (RC) 6Página de anúncio oficial
24 de Novembro de 2022Release Candidate (RC) 7--
08 de Dezembro de 2022Versão final--

Conteúdos deste artigo

Classes somente-leitura

As propriedades somente-leitura chegaram ao PHP na versão 8.1. Esta RFC é o passo adiante, que permite transformar todas as propriedades da classe em somente-leitura duma vez só.

Em vez de escrever isso:

class Codamos
{
    public function __construct(
        public readonly array $artigos,
    ) {}
}

Nós vamos passar a escrever isso:

readonly class Codamos
{
    public function __construct(
        public array $artigos,
    ) {}
}

O efeito prático do código acima é transformar todas as propriedades da classe Codamos em valores somente-leitura.

Para além disso, as classes somente-leitura tornam impossível adicionar propriedades em tempo de execução de forma dinâmica. E também só é possível herdar de uma classe somente-leitura se a sub-classe também for somente-leitura. Então o seguinte código dá erro:

$site = new Codamos();
$site->layout = 'wide'; // Gera erro

// Uncaught Error: Cannot create dynamic property Codamos::$layout

Fonte: RFC e votação da comunidade “Readonly classes”.

Adeus propriedades dinâmicas em classes

Desde que classes foram introduzidas ao PHP era possível criar propriedades de forma dinâmica como com o código abaixo:

class Codamos {}

$site = new Codamos();
$site->layout = 'wide';

Na versão 8.2 do PHP este comportamento ainda irá funcionar, mas será marcado como descontinuado (deprecated) e lançará um warning. E a partir da versão 9.0 do PHP lançará uma exceção do tipo ErrorException.

Mas não se preocupe, se o seu código precisa criar propriedades de forma dinâmica não é o fim do mundo! Você tem duas opções:

Como permitir propriedades dinâmicas no PHP 8.2 via métodos mágicos __get e __set

Desde a versão 5 do PHP, os métodos mágicos nos permitem interceptar tentativas de acessar propriedades que não existem ou não estão visíveis no escopo público de uma instância.

Você pode utilizar os métodos mágicos __get() e __set() para gravar variáveis de forma dinâmica em sua classe.

Como permitir propriedades dinâmicas no PHP 8.2 utilizando atributos

Uma forma menos trabalhosa de permitir propriedades dinâmicas em suas classes no PHP 8.2, é utilizando o atributo #[AllowDynamicProperties] que foi criado justamente para esta versão da linguagem!

A sua classe ficaria assim:

#[AllowDynamicProperties]
class Codamos {}

$site = new Codamos();
$site->layout = 'wide'; // Tudo certo aqui

Fonte: RFC e votação da comunidade “Deprecate dynamic properties”.

Extensão nova: Random para gerar números aleatórios

Antes de eu te explicar o que essa extensão resolve, deixa eu te mostrar uma coisa:

No PHP é possível gerar números aleatórios de forma determinista, utilizando uma semente (seed). Dada uma mesma semente, os números aleatórios são gerados sempre igual a cada vez que você rodar o programa. Nós podemos definir a semente através da função mt_srand(int $seed)e podemos obter um número aleatório com a função mt_rand(int $min, int $max). Assim:

mt_srand(1234); // semente = 1234
var_dump(mt_rand(1, 100)); // int(76)

Não importa quantas vezes você rodar o programa acima, o valor gerado sempre será 76.

Acontece que a implementação atual utiliza estado global dentro da VM do PHP, de forma que algumas funções podem quebrar o comportamento do gerador de números aleatórios – caso você queira saber mais sobre como o PHP funciona por debaixo dos panos, dê uma olhada no meu artigo sobre o JIT que eu explico passo a passo como funciona.

Então o seguinte código não opera como esperaríamos:

mt_srand(1234); // semente = 1234
str_shuffle('ABC'); // redefiniu a semente :')
mt_rand(1, 100); // int(7)

Estes e outros problemas são resolvidos pela extensão Random que traz uma classe Randomizer. Com ela podemos escolher qual o motor utilizar para gerar números aleatórios. Mais ou menos assim:

$motor = new Random\Engine\MarsenneTwister(1234);

$randomizer = new Random\Randomizer($motor);
var_dump($randomizer->getInt(1, 100)); // int(76)

Fonte: RFC e votação da comunidade “Random extension 5.x”.

Novos tipos: null, true e false

O php já possui os tipos void e bool que representam a ausência de retorno e a união true|false respectivamente.

A partir da versão 8.2 vamos poder explicitar melhor a assinatura de nossos métodos e funções indicando que o retorno será exatamente null, true ou false.

Um bom exemplo de função que operaria desta forma é a função fread() que retorna uma string com o conteúdo lido ou bool(false) em caso de erro. Uma assinatura válida para esta função, de acordo com o PHP 8.2, poderia ser a seguinte:

function fread($handle, int $len): string|false

Fonte: RFC e votação da comunidade “Allow null and false as stand-alone types”.

Tipos de forma normal disjuntiva (Disjunctive normal form types – DNF)

Dev é uma coisa né… que nome complicado pra uma parada simples!

Esta feature nada mais é do que permitir utilizar Union types e Intersection Types ao mesmo tempo!

A condição pra isso, é que os Intersection types estejam entre parênteses, desta forma:

function minhaFuncao((TipoA & TipoB) | false $param)

Aqui o tipo DNF é (TipoA & TipoB) | false.

A ideia é massa, mas vai começar a ficar tenso fazer esse tipo de coisa sem poder apelidar tipos. Talvez esta possa ser a próxima adição ao core – alô galera que programa em C!

Fonte: RFC e votação da comunidade “Disjunctive normal form types”.

Constantes em traits

As traits do PHP já nos permitem compartilhar propriedades e métodos. A nova adição que veio na versão 8.2 do PHP agora nos permite a criar constantes dentro de traits.

Veja o código a seguir:

trait MinhaTrait
{
    public const MINHA_CONST = 0xABC;
}

class MinhaClasse
{
    use MinhaTrait;
}

MinhaTrait::MINHA_CONST; // Erro
MinhaClasse::MINHA_CONST; // 0xABC

Portanto não é possível acessar a constante diretamente através da trait mas sim de classes que a utilizem. Importante também notar que a visibilidade das constantes (public, protected ou private) será naturalmente respeitada.

Fonte: RFC e votação da comunidade “Constants in Traits”.

Esconder parâmetros em backtraces

Quando um erro acontece na nossa aplicação, o PHP gera um backtrace que mostra método a método o que aconteceu naquela execução. As vezes alguns parâmetros não deveriam ser mostrados nos logs, por questão de segurança. Por exemplo, o log a seguir é meio perigoso:

function ftp_upload(
    string $login,
    string $senha,
    string $src,
    string $dst
) {
    throw new Exception("Não implementado.");
}

ftp_uload(getenv('FTP_LOGIN'), getenv('FTP_SENHA'), './arquivo.txt', '/home/nawarian/arquivo.txt');

Stack trace:
#0 ftp.php(58): ftp_upload('nawarian', '1337', './arquivo.txt', '/home/nawarian/arquivo.txt')

O erro acima (que eu escrevi dessa forma só pra ilustrar o problema) acaba expondo as varáveis $login e $senha no stack trace.

A partir do PHP 8.2 será possível anotar alguns parâmetros da função como sensíveis, de forma que o PHP não irá mostrar seus valores no trace. Funciona assim: você adiciona o atributo #[SensitiveParameter] ao parâmetro e o PHP cuida de todo o resto.

function ftp_upload(
    string $login,
    #[SensitiveParameter] string $senha,
    string $src,
    string $dst
) {
    throw new Exception("Não implementado.");
}

ftp_uload(getenv('FTP_LOGIN'), getenv('FTP_SENHA'), './arquivo.txt', '/home/nawarian/arquivo.txt');

Stack trace:
#0 ftp.php(58): ftp_upload('nawarian', Object(SensitiveParameterValue), './arquivo.txt', '/home/nawarian/arquivo.txt')

Note que no stack trace o segundo parâmetro, agora marcado como sensível, é apresentado como Object(SensitiveParameter).

Fonte: RFC e votação da comunidade “Redacting parameters in back traces”.

Funções utf8_encode() e utf8_decode() descontinuadas

A partir da versão 8.2 do PHP, as funções utf8_encode() e utf8_decode() serão descontinuadas e vão gerar um notice no seu Log. No futuro estas duas funções serão removidas.

A mensagem do tipo notice se parece com o seguinte:

Deprecated: Function utf8_encode() is deprecated
Deprecated: Function utf8_decode() is deprecated

Para realizar a migração, você pode optar por utilizar as função mb_convert_encoding() da extensão Multibyte String.

O grande Vinicius Dias, do canal Dias de Dev, fez um vídeo maravilhoso explicando a RFC, suas motivações e como fazer a migração:

Fonte: RFC e votação da comunidade “Deprecate and Remove utf8_encode and utf8_decode”.

Mudança no retorno dos métodos que criam datas

As classes DateTimeDateTimeImmutable possuem métodos para criar datas com as seguintes assinaturas:

DateTime::createFromImmutable(): DateTime
DateTimeImmutable::createFromMutable(): DateTimeImmutable

A partir da versão 8.2 do PHP, ambas assinaturas passarão a retornar o tipo static. Apesar de parecer não ter efeito colateral algum, isto muda fundamentalmente como podemos trabalhar com herança nas classes DateTime e DateTimeImmutable.

Esta é uma mudança que quebra compatibilidade com as versões anteriores caso seu código possua alguma herança das classes DateTime ou DateTimeImmutable.

Fonte: Manual de atualização do PHP 8.2 RC5.

Outras mudanças

Também foram introduzidas outras mudanças menores de sintaxe e manutenção geral da plataforma, para remover suporte a algumas funções.

A lista completa de mudanças você encontra no arquivo UPGRADING do repositório oficial do PHP.

Não esquece de compartilhar este artigo em suas redes e com colegas de trabalho.

Até a próxima! 👋

Comentários