Pare de usar Arrays

Por Jean Hertel, 22/02/2021

php , array

Hoje quero falar de uma estrutura de dados extremamente utilizada no PHP, o array. Para quem não conhece, o array de PHP é uma estrutura de dados muito versátil, podendo armazenar qualquer tipo de dados devido a natureza dinâmica do PHP. Vejamos alguns exemplos para entender o poder de um array PHP.

Declarando um array:

<?php
// Podemos declarar um array vazio
$example = [];

// Podemos também inicializar um array com valores
$example = [
    1, 2, 3, 5, 8
];

// Um array tem tamanho dinâmico, então podemos colocar quantos elementos queremos
$example[] = 13;

var_dump($example);
// Exemplo de output: array(1, 2, 3, 5, 8)

Os arrays em PHP na verdade são implementados utilizando um Ordered Hash Map então podemos colocar qualquer valor em qualquer posição utilizando uma chave qualquer ou deixar que o PHP gerencie as chaves. Um exemplo de array com chaves que lembra um HashMap em Java:

<?php
$example = [];
$example['a'] = 20;
$example['b'] = 50;

var_dump($example);
// Exemplo de output: array('a' => 20, 'b' => 50)

Com todo essa flexibilidade fica fácil entender porque os programadores PHP amam tanto os arrays. Porem existem vários casos em que arrays deixam muito a desejar e como tenho visto muitos casos de mal uso decide descrever alguns dos problemas comuns que encontro. Vejamos alguns exemplos.

O método que retorna diferente:

<?php
function fazAlgo() {
  if (algumaCondicao()) {
    return ['result' => 10, 'nome' => 'João'];
  }

  return ['falha' => 'Algo deu errado'];
}

$result = fazAlgo();
if (isset($result['falha'])) {
    // Gerenciar erro
}

No código acima o retorno da função fazAlgo() é diferente dependendo de uma condição interna da função. O programador que invocar esta função precisa saber quais são os resultados possíveis e testar explicitamente por eles.

O método que retorna as vezes:

<?php
function fazAlgo() {
  if (algumaCondicao()) {
    return ['sucesso' => true, 'result' => 10, 'nome' => 'João'];
  }

  return ['sucesso' => false, 'error' => 'Algo deu errado'];
}

$result = fazAlgo();
if (!$result['sucesso']) {
  // Gerenciar erro
}

Neste segundo exemplo a função fazAlgo() retorna sempre um parâmetro indicando o sucesso ou não da função, porem ainda temos mais um pequeno problema: O que diabos a função retorna?

Nos dias de hoje é extremamente comum que programadores utilizem uma IDE para auxiliar no desenvolvimento. Um dos recursos muito uteis da IDE é auto-completar o texto e indicar quando o programador comete algum erro. Infelizmente devido a esta natureza dinâmica dos arrays a IDE é incapaz de deduzir o retorno da função, forçando o programador a ler o código da função todas as vezes que precisar lembrar seu retorno.

Adicione a este problema o fato de que muitas funções invocam outras funções tornando o resultado muito difícil de deduzir pois somos forçados a ler o código de todas as funções para entender o que está acontecendo.

Estes problemas acima podem ser facilmente resolvidos se retornarmos objetos de alguma classe especifica, especialmente quando definimos o tipo de retorno. Vejamos o primeiro exemplo re-escrito:

<?php
class ProcessingResult {
  private $success = false;
  private $result = 0;
  private $name = '';
  private $error = '';

  public function isSuccess() {
    return $this->success;
  }

  public function setSuccess($success) {
    $this->success = $success;
  }

  public function getResult() {
    return $this->result;
  }

  public function setResult($result) {
    $this->result = $result;
  }

  public function getName() {
    return $this->name;
  }

  public function setName($name) {
    $this->name = $name;
  }

  public function setError($error) {
    $this->error = $error;
  }

  public function getError() {
    return $this->error;
  }
}

function fazAlgo(): ProcessingResult {
  $result = new ProcessingResult();

  if (algumaCondicao()) {
    $result->setSuccess(true);
    $result->setResult(10);
    $result->setName('João');

    return $result;
  }

  $result->setSuccess(false);
  $result->setError('Algo deu errado');

  return $result;
}


$result = fazAlgo();

if ($result->isSuccess()) {
  // Gerenciar erro
}

O código acima pode parecer extenso, porem ele deixa muito mais claro para outros programadores qual a sua real intenção alem de deixar muito claro quais valores estão disponíveis ao retornar. Como bonus as IDEs agora conseguem deduzir o tipo de retorno, bem como fornecem um auto-completar muito melhor.