PHP Higienizando Variáveis com Operador Elvis ?:

function defaultValues(int $index, string $sku, string $code, string name, int $quantity, float $price)
    $index = $index ?: 1;
    $sku = $sku ?: 'NOT INFORMED';
    $code = $code ?: 'NOT INFORMED';
    $name = $name ?: 'NOT INFORMED';
    $quantity = $quantity ?: 0;
    $price = $price ?: 0.0;
}

Há algum tempo eu vinha observando em meus códigos um uso excessivo do operador ternário para limpeza e padronização de variáveis, dai recentemente eu dei uma olhada com mais carinho no operador Elvis. Em alguns artigos eu encontrei explicações de que ele seria a parte FALSE do operador ternário, mas eu nunca tinha aplicado ele na prática de uma forma tão contundente.

Então surgiu uma nova oportunidade e fui olhar a documentação novamente e “voila”. Não é que serviu direitinho pra fazer higienização de variáveis?!

Mas por que não usar o operador ternário? Porque a higienização requer uma ação apenas e o ternário exige duas.

E o operador Null Coalesce? Bom, o null coalesce testa somente nulls e no meu caso conteúdo vazio também precisaria ser higienizado.

A melhor opção então recaiu sobre o operador Elvis, por que ele executa ação para todo e qualquer conteúdo avaliado como FALSEY. Grosseiramente falando o FALSEY equivale a qualquer conteúdo convertido para boolean que resulta em falso… veja os exemplos abaixo:

var_dump(null ?: 'null is falsey');      // "null is falsey"
var_dump(true ?: 'true is truthy');      // bool(true)
var_dump(false ?: 'false is falsey');    // "false is falsey"
var_dump('' ?: 'empty string is falsey');// "empty string is falsey"
var_dump(' '?: 'space is truthy');       // " "
var_dump(empty(null) ?: 'empty null is truthy'); // bool(true)
var_dump(0 ?: 'zero int is falsey');     // "zero int is falsey"
var_dump(0.0 ?: 'zero float is falsey'); // "zero float is falsey"

Agora compare os resultados com o NULL COALESCE…

var_dump(null ?? 'null is coalesced');        // "null is coalesced"
var_dump(true ?? 'true is not coalesced');    // bool(true)
var_dump(false ?? 'false is not coalesced');  // bool(false)
var_dump('' ?? 'empty string is not coalesced'); // ""
var_dump(' ' ?? 'space is not coalesced');       // " "
var_dump(empty(null) ?? 'empty null is not coalesced'); // bool(true)
var_dump(0 ?? 'zero is not coalesced');         // int(0)
var_dump(0.0 ?? 'zero float is not coalesced'); // float(0)

Claramente a escolha correta é usar o operador Elvis para a higienização pois nulls, zeros integer or float, boolean false, empty string, todos sem excessão irão disparar a ação para higienização, evitando assim o uso de ifs e outros testes desnecessários.

Happy CleanCode!

Elvis Operator

PHP Utilizando Operador Ternário para Executar Ações IF / ELSE

$high_consuming_resources = true;
($high_consuming_resources)
  ? set_time_limit(0)
  : set_time_limit(30);

$high_consuming_resources = false;
($high_consuming_resources)
  ? init_set('memory_limit', '2048M')
  : null;

Depois que a gente começa a trabalhar com Clean Code umas das tendências é tentar ao máximo eliminar os famigerados if / else com brackets.

Então estes dias eu estava adicionando novas features em uma classe e conforme o escopo eu poderia ou não executar um processo de acordo com os parâmetros recebidos, mas não queria dar o braço a torcer… então decidi experimentar algo diferente.

Usando um operador ternário eu simplesmente desprezei a variável para armazenar o resultado da operação. Como as minhas operações eram VOID elas não produziam nenhum retorno mesmo.

Depois foi simples, na parte TRUE / FALSE do ternário coloquei as instruções para executar as operações desejadas. Tem que ser uma operação única, ou então uma operação em cadeia tipo um objeto que retorna self e permite encadear as operações.

Caso você tenha duas ou mais operações você pode encapsulá-las em um novo método e então no ternário teria uma única operação a ser invocada.

Também surgiu a situação onde eu tinha uma operação somente para a parte TRUE do ternário. Então a solução mais lógica foi apenas adicionar um NULL na parte FALSE fechando o ciclo do operador.

O mesmo código acima poderia ser escrito desta forma com o tradicional IF / ELSE…

$high_consuming_resources = true;
if ($high_consuming_resources) {
    set_time_limit(0);
} else {
    set_time_limit(30);
}

$high_consuming_resources = false;
if ($high_consuming_resources) {
    init_set('memory_limit', '2048M');
}

E aí? Qual destas formas você acha mais legível ou mais agradável para debugar mentalmente?

Confesso que acabei me acostumando com o ternário, na hora de ler o código parece que flui melhor o raciocínio.

Sei lá, pode ser só preferência pessoal mesmo!

PHP Array Anônimo, uma técnica não tão conhecida assim…

echo [
    'index1' => 'content1',
    'index2' => 'content2',
    'index3' => 'content3',
    'index4' => 'content4',
]['index3'] ?? 'Conteúdo não encontrado';

Você consegue definir qual a saída obtida pelo código acima? Talvez não, mas não se preocupe você não está sozinho.

Esta técnica de programação nem possui um nome bem definido, o melhor que consegui identificar na internet seria Array Anônimo, mas ainda assim com muitas divergências de opiniões sobre o tema. Não importa, vamos entender como tirar proveito disto.

Primeiro vamos entender o código acima postando um exemplo mais simples.

echo [ 'index1' => 'content1']['index1'];

Melhorou? Que tal simplificar para algo mais usual, mais conhecido pelos devs.

$y = array('index1' => 'content1');
echo $y['index1'];

E agora? Ficou mais familiar? Reconhece esta sintaxe do PHP Array?

Então, Array Anônimo nada mais é do que utilizar o conteúdo de um Array sem ter que definir este conteúdo em uma variável nomeada. Vamos a mais um exemplo possível.

foreach ([
  'index1' => 'content1',
  'index2' => 'content2',
  'index3' => 'content3',
  'index4' => 'content4'
] as $index => $value) {
  echo 'Index: ' . $index . ' Value: ' . $value;
}

Até aqui o objetivo foi descrever o mecanismo do array anônimo. Acredito que foi possível entender o funcionamento do mecanismo através dos exemplos simplificados.

Mas qual a aplicação prática real desta técnica de programação? Para que serve? Como posso tirar proveito disto? Bom, a resposta é simples.

  • Qualidade de código (clean code)
  • Programação sem ramificações (branchless programming)

Para exemplificar esta aplicabilidade, vamos considerar o seguinte cenário. Temos uma aplicação que roda em múltiplos servidores e precisamos obter uma chave secreta dada uma lista de servidores.

class ServerSecret {
  public static function mySecret($servername) {
    return [ 
      'server1' => 'xyz',
      'server2' => 'wsx',
      'server3' => 'oiu',
    ][$servername] ?? self::throwInvalidServer($servername);
  }

  private static function throwInvalidServer(string $servername) {
    throw new \LogicException(
      sprintf('Servidor %s não foi encontrado', $servername);
    );
}

Pronto, temos aí uma aplicação concreta para o uso do Array Anônimo. Você não precisa se ater muito ao que o código está fazendo, até por que é possível obter o mesmíssimo resultado codificando sintaxes diferentes.

O mais importante de se observar é como o código foi organizado, limpeza, clareza, funcionalidade e principalmente a ausência de IFs e ramificações de códigos.

Para quem quiser se aprofundar um pouco mais no assunto recomendo pesquisar por Branchless Programming.