O Que Há de Novo no PHP 8 - Parte 3

27 de julho de 2022
Ronaldo B.

Chegamos ao terceiro artigo sobre as novidades do PHP 8, agora já sabendo o logo oficial desta versão da linguagem. Você pode conferir os outros dois artigos desta série nos links abaixo:

O Que Há de Novo no PHP 8 - Parte 1

O Que Há de Novo no PHP 8 - Parte 2

Neste artigo iremos falar sobre outras 8 novidades do PHP 8. Então, vamos lá!

Named Arguments

Quando trabalhamos com funções ou métodos, sempre ouvimos falar de argumentos ou parâmetros. E sabemos que a ordem que informamos esses valores pode fazer toda a diferença no bom funcionamento do código.

A linguagem PHP sempre possuiu argumentos referenciados por meio de sua posição. Mas com a versão 8, isso mudou. Agora possuímos argumentos nomeados. Isso significa que podemos deixar claro qual argumento os valores se referem. Vamos ver um exemplo disso.

Vamos criar uma função que irá retornar um array dos dados informados:

function create_user($username = "admin", $password = "admin", $is_admin = true) {
	$data = [
		'username' => $username,
		'password' => $password,
		'admin' => $is_admin
	];
	return $data;
}

Note que essa função possui um valor padrão para todos os argumentos. Imagine que desejamos realizar a chamada dessa função, mas informando apenas o argumento $password. Para fazer isso, basta informar para a função o nome do argumento sem o sinal de $, definir um sinal de : (dois-pontos) e então informar seu valor:

print_r(create_user(password: '123456'));

Esse código definirá o seguinte resultado:

Resultado de nossa função no navegador

Perceba que a informação de senha foi identificada corretamente, mas os outros dois parâmetros receberam seus valores padrão. Por meio dos argumentos nomeados também podemos informar os argumentos na ordem que desejarmos; não precisamos mais ficar presos à ordem que foi definida na função. Por exemplo, se desejarmos informar o terceiro argumento e depois o primeiro, não tem problema:

print_r(create_user(is_admin: 0, username: 'support'));

O resultado desse código será o seguinte:

Resultado de nossa função no navegador

Os dados também são reconhecidos. Impressionante, não é mesmo?

Esse mesmo padrão pode ser usado em funções nativas do PHP. Podemos ver um exemplo disso com a função array_fill(), que é usada para criar um array personalizado com os valores que determinamos. Ele espera três parâmetros: 1) start_index, que representa o índice inicial do nosso array; 2) count, que representa a quantidade de itens que o array possuirá; e 3) value, que é o valor dos itens. Se desejarmos usar os argumentos nomeados com esta função, podemos usar o seguinte código:

print_r(array_fill(value: 'Hcode', start_index: 0, count: 10));

O resultado será o seguinte:

Array gerado pela função array_fill()

Nosso array foi criado com sucesso ?.

Match Expression

A declaração switch() é uma das estruturas de controle de fluxo mais usadas em qualquer linguagem de programação, e no PHP não é diferente. Na versão 8 do PHP teremos um novo recurso que promete simplificar essa estrutura, a expressão match(). A estrutura dela lembra o switch(), mas um pouco mais simples. Vamos ver um exemplo para comparar suas sintaxes.

Imagine que desejamos criar um controle de fluxo que consiga identificar o nível de conhecimento ou carreira de um programador, classificando-o como “Júnior”, “Pleno” ou “Sênior” baseando-se em um identificador. Poderíamos fazer isso com o seguinte código:

$level_number = 3;
switch ($level_number) {
	case 1:
		$level = 'Sênior';
		break;
	case 2:
		$level = 'Pleno';
		break;
	case 3:
		$level = 'Júnior';
		break;
}
echo $level;

O resultado seria o seguinte:

Resultado de nosso switch() no navegador

Vemos que o código funcionou corretamente. Nós poderíamos escrever o mesmo código usando a expressão match desta forma:

echo match($level_number) {
	1 => 'Sênior',
	2 => 'Pleno',
	3 => 'Júnior'
};

O resultado seria o mesmo, mas note que escrevemos bem menos desta vez. Nós fizemos a chamada do construtor echo diretamente com o match(), algo que não é possível com o switch(). Além disso, não foi preciso nos preocupar com os vários breaks que são necessários no switch() para garantir que não haverá um resultado indesejado.

A expressão match() possui um outro recurso que pode ser encarado como uma boa vantagem. A declaração switch() realiza a verificação apenas dos valores que estamos comparando. A expressão match() faz a verificação de valor e também do tipo das variáveis. Isso garante que o controle de fluxo será ainda mais preciso. Vamos ver um exemplo dessa questão.

Imagine que queremos realizar a verificação do valor do número 0. Vamos compará-lo tanto com seu valor exato como também com a string deste número. Faremos isso primeiramente com o switch(), por meio deste código:

switch (0) {
	case '0':
		$result = "Essa é a string zero";
		break;
	case 0:
		$result = "Esse é o número zero";
	break;
}

echo $result;

Em sua opinião, qual será o valor retornado? Ele conseguirá entender que estamos procurando pelo número zero de fato? Quando acessamos o navegador, vemos o seguinte resultado:

Retorno de nosso switch() no navegador

O switch() identificou a string do número zero como o valor procurado, pois ele verifica apenas o valor. Vamos executar o mesmo código usando agora a expressão match():

echo match (0) {
	'0' => 'Essa é a string zero',
	0 => 'Esse é o número zero'
};

Quando acessamos o navegador, o valor retornado agora é o seguinte:

String retornada pela expressão match()

Excelente, agora sim identificamos o número zero de fato, pois o match() verifica tanto o valor como também o tipo do valor a ser comparado.

Uma outra característica da match expression é que ela permite definir mais de um caso para os valores comparados, algo que já conhecemos do switch(). Imagine por exemplo que desejamos conferir qual é o nível de acesso de um usuário baseando-nos em um número. Poderíamos fazer isso com o seguinte código:

$level_access = 2;
echo match($level_access) {
	1, 2 => 'Acesso Administrativo',
	3, 4 => 'Acesso Público'
};

Note que nesta situação nós definimos que tanto o valor 1 como 2 pode representar o “Acesso Administrativo”. Assim, ao acessar o navegador, o resultado retornado será o seguinte:

Retorno de nossa match() expression

O código funcionou corretamente! E por fim, podemos falar da questão do caso padrão, ou default. Ele também está presente na expressão match(), e pode ser definido da seguinte forma:

echo match($level_access) {
	1, 2 => 'Acesso Administrativo',
	3, 4 => 'Acesso Público',
	default => 'Acesso Público'
};

Agora, se definirmos que o acesso é 0 por exemplo, o código não irá quebrar, o resultado será o seguinte:

Retorno padrão da expressão match()

Algo interessante que podemos notar em relação ao default do match() é que, diferentemente do switch(), não é possível defini-lo junto com outros valores. Ou seja, o código abaixo não iria funcionar:

echo match($level_access) {
	1, 2 => 'Acesso Administrativo',
	3, 4, default => 'Acesso Público' // Esta parte retornaria um erro
};

Já conseguiu pensar em situações em que poderá utilizar esse novo recurso do PHP? Todas as questões que falamos acima nos ajudam a saber quando podemos usar a expressão match para simplificar nosso código. Essa é com certeza uma novidade bem interessante, não é mesmo?

Atributos nativos no PHP

Usar attributes é um costume que pode nos ajudar a deixar nosso código bem explicado. Isso pode nos ajudar também quando precisamos criar algum tipo de documentação de nossos sistemas. O PHP não tinha nenhuma ferramenta nativa que permitisse desenvolver essas anotações. Por isso, é muito comum usar ferramentas de terceiros, como o PHPDoc. Usando esse gerador de documentação, poderíamos documentar um método usando a sintaxe abaixo:

class Clients {
	/**
	* @Route("/clients", methods={"POST"})
	*/
	public function create($data) {}
}

Mas, a partir da versão 8, o PHP possuirá anotações de atributos de maneira nativa. Assim, poderíamos definir as mesmas anotações do PHPDoc usando o código abaixo:

class Clients {
	#[Route("/clients", methods: ["POST"])]
	public function create($data) {}
}

Se você tem algum amigo que costuma usar o PHPDoc e que vai gostar dessa novidade do PHP 8, não deixe de compartilhar esse artigo com ele ?.

Funções str_starts_with() e str_ends_with()

O PHP 8 também irá introduzir novas funções ao seu acervo de recursos. Duas funções bem interessantes são a str_starts_with() e str_ends_with(). Como os nomes mostram, o objetivo delas é conferir, respectivamente, se uma string inicia e se termina com uma letra ou conjunto de letras. Vamos ver um exemplo de cada uma delas.

A função str_starts_with() espera dois parâmetros: 1) uma string e 2) o conjunto de caracteres que estamos procurando em seu início. Imagine que estamos trabalhando em um sistema de cadastro e precisamos garantir que nenhum usuário poderá cadastrar um email com o nome “hcode”, pois esse será um identificador reservado para uma quantidade específica de usuários. Poderíamos usar a nova função str_starts_with() para isso, usando o seguinte código:

$email = '[email protected]';
if (str_starts_with($email, 'hco')) {
	echo 'Esse é um e-mail reservado';
}

Assim, se alguém desejar cadastrar um email que inicie com “hco”, verá a seguinte mensagem como retorno:

Mensagem retornada pela nossa verificação de email

Antigamente precisaríamos definir a chamada das funções substr() e strpos() para realizar a mesma verificação. Mas com o novo recurso do PHP 8 ficou bem mais simples, não concorda?

A função str_ends_with() também espera dois parâmetros: 1) uma string e 2) o conjunto de caracteres que estamos procurando em seu final. Para falar sobre essa, vamos pensar na seguinte situação: imagine que desejamos criar uma função que verifique se uma palavra está no plural ou no singular. Falando de maneira geral, qual parâmetro levamos em conta para descobrir se uma palavra está no plural? As palavras no plural geralmente possuirão um “s” no final. Poderíamos criar um if() ternário que verificaria essa condição usando a nova função. O código ficaria assim:

echo (str_ends_with($name, 's')) ? 'Esta palavra está no plural' : 'Esta palavra está no singular';

Assim, se definirmos a variável $name como “Computador”, veremos o seguinte resultado:

Retorno de uma variável no singular

Mas, se definirmos que ela possuirá o valor “Computadores”, o resultado será diferente:

Retorno de uma variável no plural

É claro que há exceções nesta regra quanto a saber se uma palavra está no plural ou no singular. Mas neste exemplo conseguimos notar que essa função consegue facilmente identificar os últimos caracteres de uma string e poderá nos ajudar bastante em outras situações durante o desenvolvimento.

Função str_contains()

Uma outra função que chega com o PHP 8 é a função str_contains(). O objetivo dela é verificar se uma string possui uma determinada letra ou palavra em sua estrutura. Ela espera dois parâmetros: 1) uma string e 2) a palavra que estamos procurando nela. Vamos criar um exemplo. Imagine que definimos uma frase dentro de uma variável:

$phrase = 'A linguagem PHP é sensacional!!!';

Queremos verificar se essa frase possui a palavra “PHP”. Se for esse o caso, desejamos imprimir uma mensagem na tela. Para isso, poderíamos usar o seguinte if() ternário:

if (str_contains($phrase, 'PHP')) echo 'PHP foi encontrado';

Ao acessar o navegador, veríamos o seguinte resultado:

Retorno de nossa função str_contains()

Note que a função conseguiu identificar a palavra na frase e retornou um booleano true.

Esta nova função possui um pequeno detalhe: se realizarmos a busca por uma string vazia, ela sempre irá retornar verdadeiro. Ou seja, o código abaixo sempre seria true:

if (str_contains($phrase, '')) echo 'PHP foi encontrado';

Função fdiv()

Uma outra função é a fdiv(). Ela é usada para realizar uma divisão entre dois números e sempre retorna o resultado da equação em notação de ponto flutuante. Essa função espera dois parâmetros: 1) o dividendo e 2) o divisor da equação. Veja abaixo a chamada desta função:

echo fdiv(450, 15);

Este código retorna o seguinte resultado no navegador:

Retorno de nossa equação definida no código

O resultado foi o esperado. Mas, como comentamos acima, essa função retorna o valor como ponto flutuante, ou decimal. Assim, se realizarmos a divisão de dois decimais, o valor retornado será exato. Veja por exemplo o código abaixo:

echo fdiv(4.5, 2.8);

Ele retornará o seguinte resultado:

Resultado da divisão de dois decimais

Vemos que o resultado decimal está correto. Isso não ocorreria com outras funções, como a intdiv(), que iria arredondar esse resultado para 2.

Após analisar essas características, talvez possamos pensar: “Essa função é bem interessante. Entretanto, eu consigo fazer essas mesmas operações usando o sinal de barra (/). Qual diferencial essa função pode me oferecer?”

Neste momento podemos analisar uma particularidade desta nova função, que pode ser usada para tratar um dos erros mais clássicos da programação: tentar dividir um número por zero. Se tentarmos realizar isso com o PHP, um erro será retornado, paralisando a execução do código. Contudo, se fizermos essa divisão usando a função fdiv(), teremos um resultado diferente. Veja o código abaixo:

echo fdiv(450, 0);

Normalmente veríamos um erro como retorno de sua chamada, mas quando acessamos o navegador, nos deparamos com este resultado:

Retorno com a nova função fdiv()

Nos foi retornado a string “INF”. Esse retorno ainda pode ser as strings “-INF” (se realizarmos a divisão com números negativos) ou “NAN” (se dividirmos o número 0 por 0). Esse conceito se assemelha muito ao que vemos no JavaScript, que nativamente retorna a string “Infinity” quando tentamos dividir um número por zero. É possível obter um resultado semelhante agora com o PHP 8, mas apenas se usarmos a função fdiv(). O erro de divisão por zero continua o mesmo se realizarmos essa operação sem a função.

Função get_debug_type()

A próxima função que iremos ver é a get_debug_type(). Podemos dizer que ela é uma alternativa à função gettype(), amplamente usada para identificar o tipo de dado de uma variável. Essa nova função tem o objetivo de retornar os tipos de dados de uma maneira que estamos mais acostumados a ver em outras linguagens de programação ou até mesmo em documentações. Vamos ver alguns exemplos disso.

Imagine que queremos verificar o tipo de dado de uma variável que contém um número inteiro. Vamos realizar a chamada das duas funções em nosso código:

$year = 2020;
var_dump(gettype($year)); // Maneira convencional
echo "<br/>";
var_dump(get_debug_type($year)); // Maneira nova

Ao acessar o navegador, vemos o seguinte resultado:

Retorno do valor inteiro por meio da nova função

Note que a função gettype() nos retornou “integer”. Em contrapartida, a nova função get_debug_type() nos retorna “int”, um identificador que estamos mais acostumados.

Um outro exemplo é na questão dos números decimais. Vamos ver como essas funções tratam esse tipo de dado por meio do código abaixo:

$price = 999.90;
var_dump(gettype($price));
echo "<br/>";
var_dump(get_debug_type($price));

Ao acessar o navegador, vemos o seguinte resultado:

Retorno do valor float por meio da nova função

Vemos que a função gettype() nos retornou “double”. Nós conseguimos entender esse tipo de dado, mas pode ser que estejamos mais acostumados com o tipo de dado “float”. Se esse for o nosso caso, podemos usar a função get_debug_type().

Veja abaixo como essas funções tratam um valor booleano:

$is_admin = true;
var_dump(gettype($is_admin));
echo "<br/>";
var_dump(get_debug_type($is_admin));

Este é o resultado que vemos ao acessar o navegador:

Retorno do valor bool por meio da nova função

Neste exemplo vemos que a função get_debug_type() nos retorna o valor “bool”, que também é muito comum.

Até agora os exemplos que vimos variaram de maneira sutil os tipos de dados que são retornados. Contudo, quando vemos a maneira que essas funções encaram objetos, podemos notar uma grande diferença. Vamos ver essa diferença criando uma classe chamada “Product” e verificando o tipo de dado da variável que irá conter a nova instância dela:

class Product {  }
$notebook = new Product();
var_dump(gettype($notebook));
echo "<br/>";
var_dump(get_debug_type($notebook));

Quando acessamos o navegador, vemos o seguinte resultado:

Retorno do tipo da classe por meio da nova função

 Note que a função gettype() retornou apenas “object” como o tipo da variável, de uma maneira um tanto genérica. Entretanto, a função get_debug_type() retornou o nome da classe que aquele objeto instanciou, no caso, “Product”. Bem interessante, não concorda? Esta nova função trouxe realmente recursos bem interessantes para o PHP e pode ser que encontremos durante o desenvolvimento situações em que poderemos usar essas duas funções juntas.

Função get_resource_id()

A função get_resource_id() é outra função que chega como novidade na versão 8 do PHP. Ela vem com o objetivo específico de nos ajudar a identificar o ID de um um recurso (resource) definido em nosso código. Por exemplo, imagine que criemos uma nova variável do tipo resource por realizar a leitura de um arquivo:

$file = fopen('./users.xml', "r");

Este recurso possui um ID dentro de nossa página. Antigamente, para identificar esse ID, precisávamos converter a variável do recurso para um inteiro:

var_dump((int)$file);

Esse código retornaria o ID do recurso, que poderia ser qualquer número:

ID do recurso retornado

Agora, se quisermos identificar essa informação, podemos usar essa nova função:

var_dump(get_resource_id($file));

O resultado será o mesmo:

ID do recurso retornado

Conclusão

Neste artigo aprendemos mais 8 novidades do PHP 8. Ficamos agora na expectativa de ver as incríveis aplicações que poderemos desenvolver com essa nova versão do PHP. Se você gostou do conteúdo deste artigo, por favor compartilhe-o com outras pessoas. Isso nos ajuda a continuar produzindo conteúdo sobre programação aqui em nosso Blog.

Até o próximo artigo :)

Hcode: Utilizamos cookies para a personalização de anúncios e experiências de navegação dentro de nosso site. Ao continuar navegando, você concorda com as nossas Política de Privacidade.