PHP para Iniciantes: Tipos de Dados Primitivos - Nulos

E finalmente chegamos ao último tipo de dado primitivo da nossa listinha: os nulos (null). E eu acho que esse é até mais simples de explicar, pois só tem três possibilidades para existir um "dado nulo":

  • quando você prepara uma variável sem nenhum valor:

      <?php
    
      $variavel;
    
  • quando você explicitamente cria um dado nulo:

      <?php
    
      $variavel = null;
    
  • quando você chama a função unset:

      <?php
    
      $variavel = 123;
      unset($variavel);
    

Dito isso, nulo é tudo aquilo que não possui nenhum valor.

Zero é nulo, Kiko?

Zero é zero, nulo é nulo. Mas se você comparar 0 == null, a resposta será sim.

QUÊ?

Calma aí, isso é porque essa comparação é uma comparação burra. E esse também é um assunto que vamos abordar mais pra frente. Porém eu já aceitei que não tem como explicar nada sem dar spoiler /hehe

Operadores de comparação

Algumas linguagens implementam dois comparadores bem parecidos, que é o caso do == e o === (um = a mais). PHP é uma delas. Esse tipo de existência indica que o primeiro comparador tem alguma ineficiência ou que o segundo tem alguma exigência demasiadamente elevada. Em outras palavras: se você quer uma comparação que avalie o dado na compreensão humana, o == é o que mais atende. Já na compreensão da máquina, seria o ===. Sim, você pode entender dessa forma.

O que acontece, na prática, é que o primeiro comparador (também chamado comparador abstrato) aceita comparar diferentes tipos de dados. E no final das contas, quando os tipos a comparar são diferentes, ele faz uma correção de tipagem. Geralmente nós usamos esse comparador quando não temos pleno domínio do tipo de dado que está atribuído nas variáveis ao longo do fluxo do código. E ao ler dessa forma, você deve ter imaginado que 1 bilhão de == custam mais que 1 milhão de ===, certo?

ERRRROOOOUUUU!

Porque o === é o mesmo que fazer gettype(isso) == gettype(aquilo) && (isso) == (aquilo), por isso custa mais.

Enfim, esse segundo comparador também é chamado de comparador rigoroso. Se você comparar um int com float, já dará falso pela diferença das tipagens, mesmo que o dado em si seja muito parecido.

Ok, Kiko, mas como chegamos a 0 == null?

Pela correção de tipagem! Acontece que 0 é 0b0 e null também é 0b0 (se não reconheceu essa sintaxe, volte para o artigo sobre Int). Da mesma forma, uma string vazia daria o mesmo resultado, pois seu byte seria 0b0.

Então todos os tipos de dados podem ser iguais a null, Kiko?

Quase todos. Lembre-se que também temos tipos de dados que não podem ser convertidos, que é o caso do resource e do callable. object também não é tido como nulo por representar sempre uma instância de uma classe (mesmo que seja a stdClass), então seu binário nunca é 0b0. Os demais...

<?php
$booleano = false;
$inteiro = 0;
$pontoFlutuante = 0.0;
$texto = '';
$array = [];

if ($booleano == null) {
    echo "false=null" . PHP_EOL;
}

if ($inteiro == null) {
    echo "0=null" . PHP_EOL;
}

if ($pontoFlutuante == null) {
    echo "0.0=null" . PHP_EOL;
}

if ($texto == null) {
    echo "''=null". PHP_EOL;
}

if ($array == null) {
    echo "[]=null" . PHP_EOL;
}

Note que não há menção a iterable porque seus dados são composições em array ou object, que já foram mencionados no exemplo ou no aviso lá em cima.

Legal! E se fosse ===, Kiko?

Aí todos dariam false. Porque somente null === null. Compreendido?

Como escrever NULL?

Em algumas linguagens, a forma de escrita desse tipo de dados é específica. Já no PHP, basta ter escrever NULL sem nenhuma distinção de letras maiúsculas ou minúsculas. Eu particularmente prefiro escrever NULL, mas nos exemplos coloquei propositalmente null para lembrar que somos livres.

Pra que serve NULL?

Primeiramente deixe-me te contar uma história interessante. Uns anos atrás, precisei dar manutenção em um código-fonte bem antigo e descobri que o programador que fez o projeto muitas vezes invocava variáveis que não existiam. Eu pensava: como raios isso não dá erro? Nem sequer um warning.

A questão é que ele omitivia os avisos - conforme recomendado para ambientes em produção: NUNCA MOSTRE A MENSAGEM DE ERRO DO INTERPRETADOR!! Porém ele acreditava que não tinha problema algum fazer isso, pois quando o interpretador tenta ler uma variável que não existe, ele a cria com o valor NULL.

Se null não existisse, essa situação seria impossível de acontecer. Basicamente, esse é o dado que representa a ausência de dados e muitas vezes precisamos desse tipo de recurso. Por exemplo: se você quer construir um objeto e marcar nele a data e hora que ele foi excluído e confirmar se ele foi excluído, como você faria?

Bom, você certamente poderia criar um campo string $data e um campo bool $foiDeletado, confere? Pra saber se foi deletado, checaria o booleano. Pra saber quando, checaria a data.

E se eu te disse que bastaria o campo de data? Se a data for nula, ele nunca foi excluído. Caso contrário, foi e você já sabe quando!

Por sinal, isso se chama Soft Delete. Recomendo a leitura sobre isso.

Então null tem um papel essencial em nossas vidas. Jamais menospreze isso.

E é isso! Embora pareça que falamos tudo sobre tipos de dados primitivos, ainda tem alguns assuntos a abordar sobre isso! Um desses assuntos é sobre a interpretação rigorosa do PHP, a tão famosa use strict. Tá curioso? Bom, pode pesquisar. Por hoje é só.

Inté!