Estamos de volta com a segunda parte do artigo com as novas funcionalidades do PHP 7.4. Se você ainda não leu o artigo PHP 7.4: novas funcionalidades – Parte 1 acesse agora mesmo. Lá falamos sobre arrow functions, spread operator, typed properties e também como executar os containers para testar os exemplos daquele e deste artigo. Vamos adiante porque ainda temos muito para ver! 🙂
Operador de atribuição null coalesce
Primeiramente, para explicar sobre o operador de atribuição null coalesce vamos voltar um pouco ao passado. Suponhamos que em determinado trecho do seu código uma variável recebe um valor (que também pode ser nulo). Você se lembra como poderíamos verificar o valor dessa variável e caso esse valor fosse nulo, atribuir um valor default? Pois bem, poderia ser feito dessa forma:
<?php $valor = null; $valor = !is_null($valor) ? $valor : 'valor-default'; print_r($valor); //valor-default |
Entretanto, a partir do PHP 7.0 passamos a contar com o operador null-coalesce, que nos permite atribuir um valor default caso o valor da que está sendo verificado seja nulo. Sem a necessidade da utilização do operador ternário, dessa forma:
<?php $valor = null; $valor = $valor ?? 'valor-default'; print_r($valor); //valor-default |
Atualmente na versão 7.4, para tornar essa expressão ainda menor eis que surge o operador de atribuição null coalesce, permitindo que façamos a verificação e a atribuição com um único operador. Para verificarmos seu funcionamento vamos criar o arquivo null-coalesce-assignment-operator.php no diretório app com o conteúdo abaixo:
null-coalesce-assignment-operator.php
<?php $valor = null; $valor ??= 'valor-default'; print_r($valor); //valor-default |
Ao executar a página http://localhost/null-coalesce-assignment-operator.php você terá o mesmo resultado que nos exemplos anteriores. Porém, repare que é necessário escrever menos pois esse operador é uma espécie de junção dos operador null coalesce com o operador de atribuição.
Weak References
Na versão 7.4 foi introduzida a classe WeakReference, que fornece suporte nativo a Weak References. Até então, o uso de tal recurso só era possível através de extensões, como a pecl-weakref. Weak References permitem manter a referência a um objeto sem prevenir que este próprio objeto seja “destruído” ou, falando de uma maneira mais amistosa, que seja coletado pelo Garbage Collector. Vamos lá, sei que parece meio confuso mas vamos tentar clarificar o entendimento desse conceito. Imagine que criamos um objeto do tipo StdClass e armazenamos em uma variável $a e depois atribuímos esse objeto contido em $a na variável $b, dessa forma:
<?php $a = new StdClass; $b = $a; print_r($b); // stdClass Object() /** * O que aconteceria se você destruísse o objeto contido em $a * usando a função unset? */ print_r($b); // ??? |
Você saberia dizer o que aconteceria caso destruíssemos o objeto contido na variável $a usando a função unset? Qual seria o valor de $b na última linha? Posso lhe adiantar que a variável $b manteria o objeto do tipo StdClass, pois o default behavior são as referências fortes (Strong References, em inglês), o que impede que o objeto contido na variável $b seja elegível ao Garbage Collector. Dessa forma, o objeto é mantido e o resultado pode ser verificado abaixo:
.
<?php $a = new StdClass; $b = $a; var_dump($b); // stdClass Object() unset($a); var_dump($b); // stdClass Object() |
Entretanto, há algumas situações onde necessitamos utilizar Weak References para garantir que objetos sejam elegíveis ao Garbage Collector e possam então ser “removidos” da memória. Weak references são muito úteis para implementar estruturas de cache e otimizar o uso de memória, inclusive, uma aplicação bem comum é para resolver um problema conhecido como Lapsed Listener.
Esse problema tem origem no Observer Pattern, pois em um cenário comum um observador precisa se registrar a um publicador para receber eventos e cancelar seu registro caso não queira mais ser informado sobre esses eventos. O problema ocorre quando há uma falha nesse processo de cancelamento de registro. Se estivermos usando Strong References, ainda que esse observador finalize seu ciclo de vida, sua referência ainda será mantida no publicador, causando não somente memory leak mas também a degradação da aplicação, com um observador recebendo eventos que não deseja.
Isso poderia ser facilmente contornado usando Weak References, pois ainda que exista a falha no cancelamento do registro, quando esse observador chegar ao final do ciclo de vida, sua referência poderá ser coletada pelo Garbage Collector, evitando memory leak e o recebimento indesejado desses eventos.
Concluindo, apenas para demonstrar seu uso e levando em consideração o código acima (Strong Reference) vamos criar o arquivo weak-references.php no diretório app com o seguinte conteúdo:
weak-references.php
<?php $a = new stdClass; $b = WeakReference::create($a); var_dump($b->get()); // stdClass Object() unset($a); var_dump($b->get()); // NULL |
Perceba que para criar nossa referência fraca usamos o método estático create da classe WeakReference, passando como argumento o objeto referenciado. No primeiro var_dump recuperamos a referência usando o método get e temos como resultado nosso objeto do tipo stdClass. Entretanto, após destruirmos o objeto contido na variável $a, reparem que o conteúdo de $b é igual a NULL, pois como dito anteriormente, as Weak References permitem manter a referência a um objeto sem impedir que este próprio objeto seja destruído (ou coletado).
Conclusão
No segundo post sobre as novidades do PHP 7.4 vimos mais duas funcionalidades bem legais: o operador de atribuição null coalesce e weak references. Já vimos tantas coisas até aqui que aposto que você deve estar achando que chegamos ao fim, certo? Errado! Posteriormente teremos o nosso “Grand Finale” em um terceiro post, onde abordaremos algumas funcionalidades bem especiais. Ficaram curiosos? Então não percam nosso próximo post!