Bikcraft Menu

O que há de novo no PHP 8.

4 de abril de 2022 | 0 Arlei Santos

O que há de novo no PHP 8.

O que há de novo no PHP 8

Por causa das mudanças de última hora, há uma chance maior de você precisar fazer algumas alterações em seu código para executá-lo no PHP 8.

O PHP 8 foi lançado em 26 de novembro de 2020. Você pode baixá-lo aqui . É uma nova versão principal, o que significa que há algumas mudanças importantes, bem como muitos novos recursos e melhorias de desempenho.

Por causa das mudanças de última hora, há uma chance maior de você precisar fazer algumas alterações em seu código para executá-lo no PHP 8. Se você se manteve atualizado com os últimos lançamentos, a atualização não deve ser muito difícil, já que a maioria das mudanças importantes foram preteridas antes nas versões 7.*. E não se preocupe, todas essas reprovações estão listadas neste post.

Além de mudanças radicais, o PHP 8 também traz um bom conjunto de novos recursos, como o compilador JIT , tipos de união , atributos e muito mais.

Estou criando uma minissérie de quatro partes no YouTube sobre genéricos em PHP: o que são, como podemos usá-los hoje e o que é possível no futuro. Dá uma olhada, não esqueça de deixar o like!

Genéricos em profundidade

#Novas características
Vamos começar com todos os novos recursos, é uma lista e tanto!


#Tipos de uniãorfc
Dada a natureza dinamicamente tipada do PHP, existem muitos casos em que os tipos de união podem ser úteis. Os tipos de união são uma coleção de dois ou mais tipos que indicam que qualquer um deles pode ser usado.

public function foo(Foo|Bar $input): int|float;
Observe que voidnunca pode fazer parte de um tipo de união, pois indica "nenhum valor de retorno". Além disso, nullableas uniões podem ser escritas usando |null, ou usando a ?notação existente:

public function foo(Foo|null $foo): void;

public function bar(?Bar $bar): void;
#JITrfc
O compilador JIT — just in time — promete melhorias significativas de desempenho, embora nem sempre dentro do contexto de solicitações da web. Eu fiz meus próprios benchmarks em aplicativos da web da vida real, e parece que o JIT não faz muita diferença, se houver, nesses tipos de projetos PHP.

Se você quiser saber mais sobre o que o JIT pode fazer pelo PHP, você pode ler outro post que escrevi sobre isso aqui .


#O operador nullsaferfc
Se você está familiarizado com o operador de coalescência nula, você já está familiarizado com suas deficiências: ele não funciona em chamadas de método. Em vez disso, você precisa de verificações intermediárias ou depende de optionalauxiliares fornecidos por alguns frameworks:

$startDate = $booking->getStartDate();

$dateAsString = $startDate ? $startDate->asDateTimeString() : null;
Com a adição do operador nullsafe, agora podemos ter um comportamento do tipo coalescência nulo nos métodos!

$dateAsString = $booking->getStartDate()?->asDateTimeString();
Você pode ler tudo sobre o operador nullsafe aqui .


#Argumentos nomeadosrfc
Argumentos nomeados permitem que você passe valores para uma função, especificando o nome do valor, para que você não precise levar em consideração sua ordem, e também pode pular parâmetros opcionais!

function foo(string $a, string $b, ?string $c = null, ?string $d = null)
{ /* … */ }

foo(
b: 'value b',
a: 'value a',
d: 'value d',
);
Você pode ler sobre eles em profundidade neste post .


#Atributosrfc
Atributos , comumente conhecidos como anotações em outras linguagens, oferecem uma maneira de adicionar metadados a classes, sem ter que analisar docblocks.

Quanto a uma olhada rápida, aqui está um exemplo de como são os atributos, da RFC:

use App\Attributes\ExampleAttribute;

#[ExampleAttribute]
class Foo
{
#[ExampleAttribute]
public const FOO = 'foo';

#[ExampleAttribute]
public $x;

#[ExampleAttribute]
public function foo(#[ExampleAttribute] $bar) { }
}
#[Attribute]
class ExampleAttribute
{
public $value;

public function __construct($value)
{
$this->value = $value;
}
}
Observe que essa base Attributecostumava ser chamada PhpAttributena RFC original, mas foi alterada com outra RFC posteriormente. Se você quiser se aprofundar em como os atributos funcionam e como você pode criar seus próprios; você pode ler sobre atributos em profundidade neste blog.

Notou um tpyo? Você pode enviar um PR para corrigi-lo. Se você quiser se manter atualizado sobre o que está acontecendo neste blog, você pode me seguir no Twitter ou assinar minha newsletter:E-mail Se inscrever
 

#Expressão de correspondênciarfc
Você poderia chamá-lo de irmão mais velho da switchexpressão: matchpode retornar valores, não requer breakinstruções, pode combinar condições, usa comparações de tipo estritas e não faz nenhuma coerção de tipo.

Se parece com isso:

$result = match($input) {
0 => "hello",
'1', '2', '3' => "world",
};
Você pode ler a expressão de correspondência em detalhes aqui .


#Promoção da propriedade do construtorrfc
Este RFC adiciona açúcar sintático para criar objetos de valor ou objetos de transferência de dados. Em vez de especificar propriedades de classe e um construtor para elas, o PHP agora pode combiná-las em uma.

Em vez de fazer isso:

class Money 
{
public Currency $currency;

public int $amount;

public function __construct(
Currency $currency,
int $amount,
) {
$this->currency = $currency;
$this->amount = $amount;
}
}
Agora você pode fazer isso:
class Money 
{
public function __construct(
public Currency $currency,
public int $amount,
) {}
}
Há muito mais para contar sobre promoção de imóveis, você pode ler sobre eles neste post dedicado .

#Novo statictipo de retornorfc
Embora já fosse possível retornar self, staticnão era um tipo de retorno válido até o PHP 8. Dada a natureza dinamicamente tipada do PHP, é um recurso que será útil para muitos desenvolvedores.
class Foo
{
public function test(): static
{
return new static();
}
}

#Novo mixedtiporfc
Alguns podem chamar isso de um mal necessário: o mixedtipo faz com que muitos tenham sentimentos contraditórios. Há um argumento muito bom para isso: um tipo ausente pode significar muitas coisas em PHP:

Uma função não retorna nada ou null
Estamos esperando um dos vários tipos
Estamos esperando um tipo que não pode ser tipado em PHP
Por causa das razões acima, é bom que o mixedtipo seja adicionado. mixedem si significa um destes tipos:

array
bool
callable
int
float
null
object
resource
string
Observe que mixedtambém pode ser usado como parâmetro ou tipo de propriedade, não apenas como tipo de retorno.

Observe também que, como mixedjá inclui null, não é permitido torná-lo anulável. O seguinte irá acionar um erro:

// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.
function bar(): ?mixed {}

#Lançar expressãorfc
Este RFC muda throwde uma declaração para uma expressão, o que torna possível lançar exceção em muitos novos lugares:

$triggerError = fn () => throw new MyError();

$foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset');

#Herança com métodos privadosrfc
Anteriormente, o PHP costumava aplicar as mesmas verificações de herança em métodos públicos, protegidos e privados. Em outras palavras: métodos privados devem seguir as mesmas regras de assinatura de métodos que métodos protegidos e públicos. Isso não faz sentido, já que métodos privados não serão acessíveis por classes filhas.

Este RFC mudou esse comportamento, de modo que essas verificações de herança não são mais executadas em métodos privados. Além disso, o uso de final private functiontambém não fazia sentido, portanto, agora acionará um aviso:

Warning: Private methods cannot be final as they are never overridden by other classes

#Mapas fracosrfc
Construído sobre o RFC de referências fracas que foi adicionado no PHP 7.4, uma WeakMapimplementação é adicionada no PHP 8. WeakMapcontém referências a objetos, o que não impede que esses objetos sejam coletados como lixo.

Veja o exemplo dos ORMs, eles geralmente implementam caches que mantêm referências a classes de entidade para melhorar o desempenho das relações entre entidades. Esses objetos de entidade não podem ser coletados como lixo, desde que esse cache tenha uma referência a eles, mesmo que o cache seja a única coisa que os referencia.

Se essa camada de cache usar referências e mapas fracos, o PHP coletará esses objetos quando nada mais os referenciar. Especialmente no caso de ORMs, que podem gerenciar várias centenas, senão milhares de entidades dentro de uma solicitação; mapas fracos podem oferecer uma maneira melhor e mais amigável de lidar com esses objetos.

Veja como são os mapas fracos, um exemplo do RFC:

class Foo 
{
private WeakMap $cache;

public function getSomethingWithCaching(object $obj): object
{
return $this->cache[$obj]
??= $this->computeSomethingExpensive($obj);
}
}

#Permitindo ::classem objetosrfc
Um novo recurso pequeno, mas útil: agora é possível usar ::classem objetos, em vez de ter que usar get_class()neles. Funciona da mesma forma que get_class().

$foo = new Foo();

var_dump($foo::class);

#Capturas sem capturarfc
Sempre que você quisesse capturar uma exceção antes do PHP 8, você tinha que armazená-la em uma variável, independentemente de ter usado essa variável ou não. Com capturas sem captura, você pode omitir a variável, então, em vez disso:

try {
// Something goes wrong
} catch (MySpecialException $exception) {
Log::error("Something went wrong");
}
Agora você pode fazer isso:
try {
// Something goes wrong
} catch (MySpecialException) {
Log::error("Something went wrong");
}
Observe que é necessário sempre especificar o tipo, você não tem permissão para ter um arquivo catch. Se você quiser capturar todas as exceções e erros, você pode usar Throwablecomo o tipo de captura.


#Vírgula à direita nas listas de parâmetrosrfc
Já possível ao chamar uma função, o suporte de vírgula à direita ainda estava faltando nas listas de parâmetros. Agora é permitido no PHP 8, o que significa que você pode fazer o seguinte:

public function(
string $parameterA,
int $parameterB,
Foo $objectfoo,
) {
// …
}
Como uma nota lateral: vírgulas à direita também são suportadas na uselista de fechamentos, isso foi um descuido e agora adicionado por meio de um RFC separado .


#Criar DateTimeobjetos da interface
Você já pode criar um DateTimeobjeto a partir de um DateTimeImmutableobjeto usando , mas o contrário era complicado. Ao adicionar e agora há uma maneira generalizada de converter e objetos entre si.

DateTime::createFromImmutable($immutableDateTime)

DateTime::createFromInterface()

DatetimeImmutable::createFromInterface()

DateTimeDateTimeImmutable

DateTime::createFromInterface(DateTimeInterface $other);

DateTimeImmutable::createFromInterface(DateTimeInterface $other);

#Nova Stringableinterfacerfc
A Stringableinterface pode ser usada para digitar qualquer dica que implemente __toString(). Sempre que uma classe implementa __toString(), ela implementa automaticamente a interface nos bastidores e não há necessidade de implementá-la manualmente.

class Foo
{
public function __toString(): string
{
return 'foo';
}
}

function bar(string|Stringable $stringable) { /* … */ }

bar(new Foo());
bar('abc');

#Nova str_contains()funçãorfc
Alguns podem dizer que está muito atrasado, mas finalmente não precisamos strpos()mais confiar para saber se uma string contém outra string.

Em vez de fazer isso:

if (strpos('string with lots of words', 'words') !== false) { /* … */ }
Agora você pode fazer isso

if (str_contains('string with lots of words', 'words')) { /* … */ }

#Novo str_starts_with()e str_ends_with()funçõesrfc
Dois outros muito atrasados, essas duas funções agora são adicionadas ao núcleo.

str_starts_with('haystack', 'hay'); // true
str_ends_with('haystack', 'stack'); // true

#Nova fdiv()funçãorp
A nova fdiv()função faz algo semelhante às funções fmod()and intdiv(), que permite a divisão por 0. Em vez de erros, você obterá INF, -INFou NAN, dependendo do caso.


#Nova get_debug_type()funçãorfc
get_debug_type()retorna o tipo de uma variável. Parece que algo gettype()faria? get_debug_type()retorna uma saída mais útil para arrays, strings, classes anônimas e objetos.

Por exemplo, chamar gettype()uma classe \Foo\Barretornaria object. Using get_debug_type()retornará o nome da classe.

Uma lista completa das diferenças entre get_debug_type()e gettype()pode ser encontrada na RFC.


#Nova get_resource_id()funçãorp
Os recursos são variáveis ​​especiais em PHP, referentes a recursos externos. Um exemplo é uma conexão MySQL, outro um identificador de arquivo.

Cada um desses recursos recebe um ID, embora anteriormente a única maneira de saber esse ID era converter o recurso para int:

$resourceId = (int) $resource;
O PHP 8 adiciona as get_resource_id()funções, tornando esta operação mais óbvia e segura para o tipo:

$resourceId = get_resource_id($resource);

#Métodos abstratos em melhorias de característicasrfc
Os traços podem especificar métodos abstratos que devem ser implementados pelas classes que os utilizam. Porém, há uma ressalva: antes do PHP 8, a assinatura dessas implementações de métodos não era validada. Foi válido o seguinte:

trait Test {
abstract public function test(int $input): int;
}
class UsesTrait
{
use Test;
public function test($input)
{
return $input;
}
}
O PHP 8 executará a validação de assinatura de método adequada ao usar um trait e implementar seus métodos abstratos. Isso significa que você precisará escrever isso:
class UsesTrait
{
use Test;
public function test(int $input): int
{
return $input;
}
}

#Implementação do objeto detoken_get_all() rfc
A token_get_all()função retorna uma matriz de valores. Este RFC adiciona uma PhpTokenclasse com um método. Essa implementação funciona com objetos em vez de valores simples. Ele consome menos memória e é mais fácil de ler.PhpToken::tokenize()


#Ajustes de sintaxe variávelrfc
Do RFC: "o RFC de Sintaxe de Variável Uniforme resolveu uma série de inconsistências na sintaxe de variável do PHP. Este RFC pretende abordar um pequeno punhado de casos que foram negligenciados."


#Digite anotações para funções internasexternos
Muitas pessoas contribuíram para adicionar anotações de tipo adequado a todas as funções internas. Este era um problema de longa data e finalmente solucionável com todas as alterações feitas no PHP nas versões anteriores. Isso significa que funções e métodos internos terão informações de tipo completas em reflexão.


#ext-jsonsempre disponívelrfc
Anteriormente era possível compilar PHP sem a extensão JSON habilitada, isso não é mais possível. Como o JSON é tão amplamente usado, é melhor que os desenvolvedores sempre possam confiar que ele esteja lá, em vez de ter que garantir que a extensão exista primeiro.

#Mudanças de última hora
Como mencionado anteriormente: esta é uma atualização importante e, portanto, haverá alterações importantes. A melhor coisa a fazer é dar uma olhada na lista completa de mudanças no documento UPGRADING .

Muitas dessas mudanças importantes foram preteridas nas versões 7.* anteriores, portanto, se você se manteve atualizado ao longo dos anos, não deve ser tão difícil atualizar para o PHP 8.

 

Estou criando uma minissérie de quatro partes no YouTube sobre genéricos em PHP: o que são, como podemos usá-los hoje e o que é possível no futuro. Dá uma olhada, não esqueça de deixar o like!

Genéricos em profundidade
 

#Erros de tipo consistentesrfc
As funções definidas pelo usuário no PHP já lançarão TypeError, mas as funções internas não, elas emitiram avisos e retornaram null. A partir do PHP 8, o comportamento das funções internas tornou-se consistente.


#Avisos de motor reclassificadosrfc
Muitos erros que anteriormente apenas acionavam avisos ou avisos foram convertidos em erros apropriados. Os seguintes avisos foram alterados.

Variável indefinida: aviso em vez de aviso
Índice de array indefinido: aviso em vez de aviso
Divisão por zero: DivisionByZeroErrorexceção em vez de aviso
Tentativa de incrementar/diminuir a propriedade '%s' de não objeto: Errorexceção em vez de aviso
Tentativa de modificar a propriedade '%s' de não objeto: Errorexceção em vez de aviso
Tentativa de atribuir a propriedade '%s' de não objeto: Errorexceção em vez de aviso
Criando objeto padrão a partir de valor vazio: Errorexceção em vez de aviso
Tentando obter a propriedade '%s' do não-objeto: aviso em vez de aviso
Propriedade indefinida: %s::$%s: aviso em vez de aviso
Não é possível adicionar elemento ao array porque o próximo elemento já está ocupado: Errorexceção em vez de aviso
Não é possível anular o deslocamento em uma variável que não seja de matriz: Errorexceção em vez de aviso
Não é possível usar um valor escalar como uma matriz: Errorexceção em vez de aviso
Apenas arrays e Traversablespodem ser descompactados: TypeErrorexceção em vez de aviso
Argumento inválido fornecido para foreach(): TypeErrorexceção em vez de aviso
Tipo de compensação ilegal: TypeErrorexceção em vez de aviso
Tipo de deslocamento ilegal em isset ou vazio: TypeErrorexceção em vez de aviso
Tipo de deslocamento ilegal em não definido: TypeErrorexceção em vez de aviso
Conversão de array para string: aviso em vez de aviso
ID do recurso#%d usado como deslocamento, conversão para inteiro (%d): aviso em vez de aviso
Ocorreu conversão de deslocamento de string: aviso em vez de aviso
Deslocamento de string não inicializado: %d: aviso em vez de aviso
Não é possível atribuir uma string vazia a um deslocamento de string: Errorexceção em vez de aviso
O recurso fornecido não é um recurso de fluxo válido: TypeErrorexceção em vez de aviso

#O operador @ não silencia mais erros fatais
É possível que esta mudança revele erros que estavam novamente ocultos antes do PHP 8. Certifique-se de configurar em seus servidores de produção!display_errors=Off


#Nível de relatório de erros padrão
É agora E_ALLem vez de tudo, mas E_NOTICEe E_DEPRECATED. Isso significa que muitos erros podem aparecer que antes eram ignorados silenciosamente, embora provavelmente já existissem antes do PHP 8.


#Modo de erro PDO padrãorfc
Do RFC: O modo de erro padrão atual para PDO é silencioso. Isso significa que quando ocorre um erro de SQL, nenhum erro ou aviso pode ser emitido e nenhuma exceção lançada, a menos que o desenvolvedor implemente seu próprio tratamento de erro explícito.

Este RFC altera o erro padrão para no PHP 8.PDO::ERRMODE_EXCEPTION


#Precedência de concatenaçãorfc
Embora já tenha sido obsoleto no PHP 7.4, essa alteração agora está em vigor. Se você escrevesse algo assim:

echo "sum: " . $a + $b;
O PHP anteriormente interpretaria assim:

echo ("sum: " . $a) + $b;
O PHP 8 fará com que seja interpretado assim:

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

#Verificações de tipo mais rígidas para operadores aritméticos e bit a bitrfc
Antes do PHP 8, era possível aplicar operadores aritméticos ou bit a bit em arrays, recursos ou objetos. Isso não é mais possível e lançará um TypeError:

[] % [42];
$object + 4;

#Nomes com namespace sendo um único tokenrfc
O PHP costumava interpretar cada parte de um namespace (separado por uma barra invertida \) como uma sequência de tokens. Este RFC mudou esse comportamento, significando que nomes reservados agora podem ser usados ​​em namespaces.


#Strings numéricas mais sãsrfc
O sistema de tipos do PHP tenta fazer muitas coisas inteligentes quando encontra números em strings. Este RFC torna esse comportamento mais consistente e claro.


#String mais sã para comparações de númerosrfc
Este RFC corrige o caso muito estranho em PHP onde 0 == "foo"resulta em true. Existem alguns outros casos extremos como esse, e este RFC os corrige.


#Alterações de reflexão
Alguns métodos de reflexão foram preteridos:

ReflectionFunction::isDisabled()
ReflectionParameter::getClass()
ReflectionParameter::isCallable()
Agora você deve usar ReflectionTypepara obter informações sobre o tipo de um parâmetro:

$reflectionParameter->getType()->allowsNull();
Se o tipo for um tipo único, retornará uma instância de , da qual você pode obter seu nome e se está integrado:ReflectionParameter::getType()ReflectionNamedType

$reflectionParameter->getType()->getName();
$reflectionParameter->getType()->isBuiltin();
No entanto, se o tipo for um tipo de união, você obterá uma instância de ReflectionUnionType, que pode fornecer uma matriz ReflectionNamedTypeassim:

$reflectionParameter->getType()->getTypes();
Verificar se um tipo é uma união ou não pode ser feito com uma instanceofverificação:

if ($reflectionParameter->getType() instanceof ReflectionNamedType) { 
// It's a single type
}
if ($reflectionParameter->getType() instanceof ReflectionUnionType) {
// It's a union type
}
Em seguida, três assinaturas de método de classes de reflexão foram alteradas:

ReflectionClass::newInstance($args);
ReflectionFunction::invoke($args);
ReflectionMethod::invoke($object, $args);
Agora se tornaram:

ReflectionClass::newInstance(...$args);
ReflectionFunction::invoke(...$args);
ReflectionMethod::invoke($object, ...$args);
O guia de atualização especifica que, se você estender essas classes e ainda quiser oferecer suporte ao PHP 7 e ao PHP 8, as seguintes assinaturas serão permitidas:

ReflectionClass::newInstance($arg = null, ...$args);
ReflectionFunction::invoke($arg = null, ...$args);
ReflectionMethod::invoke($object, $arg = null, ...$args);

Estou criando uma minissérie de quatro partes no YouTube sobre genéricos em PHP: o que são, como podemos usá-los hoje e o que é possível no futuro. Dá uma olhada, não esqueça de deixar o like!

Genéricos em profundidade
 


#Classificação estávelrfc
Antes do PHP 8, os algoritmos de ordenação eram instáveis. Isso significa que a ordem dos elementos iguais não foi garantida. O PHP 8 muda o comportamento de todas as funções de ordenação para ordenação estável.


#Erro fatal para assinaturas de métodos incompatíveisrfc
Do RFC: Erros de herança devido a assinaturas de método incompatíveis atualmente lançam um erro fatal ou um aviso dependendo da causa do erro e da hierarquia de herança.

Tags