PHP Array Walk Sanitizar Objeto de forma recursiva

function sanitizeObject($object): void {
  array_walk($object, function($value, $key) use($object) {
    if (is_object($value) || is_array($value)) {
      self::sanitizeObject($value);
    }

    if ($value === null
        || (is_string($value) && empty($value))
        || (is_array($value) && !$value)
        || (is_object($value) && !(array)$value)
    ) {
      unset($object->{$key});
    }
  });
}

Bom pessoal, ao invés de explicar o que este código faz vou tentar explicar qual era o problema que eu tinha de resolver, acho que dessa forma o artigo fará mais sentido pra quem estiver lendo.

Eu estava trabalhando numa integração entre sistemas e a API que recebia as informações era bastante sensível quanto ao conteúdo da request. Por exemplo, o comportamento da API poderia variar muito entre eu enviar uma propriedade com conteúdo NULL ou então com a propriedade com conteúdo vazio. Em ambos os casos o melhor cenário seria não enviar a propriedade na request.

Já no início recebi uma dica de usar o array_filter para eliminar as propriedades nulas ou vazias, como este código aqui por exemplo:

function clearNullFields($metadata) {
  return (object)array_filter((array)$metadata, static function ($value) {
    return !(null === $value || trim($value) === '');
  });
}

O array_filter até poderia resolver a questão, isso se o objeto tivesse um único nível. Mas não era esse o caso, uma request de API normalmente é composta por vários outros objetos em múltiplos níveis.

Depois de pesquisar um pouco me deparei com um artigo onde a solução era dada por um array_walk. Bingo!

Bastou esta centelha e um pouco de criatividade para adicionar a recursividade fazendo com que todas as propriedades nulas ou vazias fossem sistematicamente removidas com unset.

Até mesmo um objeto mais interno cujas propriedades eram todas nulas ou vazias acabou sendo completamente removido. Isto porque a recursividade resolve as remoções do nível mais baixo para o nivel mais alto.

Assim após remover todas as propriedades escalares de um objeto, ele mesmo será um objeto vazio. Consequentemente ao retornar da recursividade inferior o objeto estará vazio e será removido exatamente por este motivo.

Mas um aviso importante!

O array_walk opera sobre o objeto fornecido alterando suas características originais. Assim para não comprometer nenhum processo que utilizasse o objeto original a solução foi criar um objeto totalmente novo para ser sanitizado. Como?

$sanitize = \json_decode(\json_encode($original));
sanitizeObject($sanitize);

Fantástico, funciona melhor do que o programado!

Deixe um comentário