PHP

usort PHP: ordenar array de arrays por um campo com o spaceship

Lista de produtos vinda do banco, cada item um array associativo com nome e preco, e você precisa mostrar do mais barato pro mais caro. Dá pra fazer com array_multisort, só que aí você é obrigado a extrair uma coluna de preços antes, só pra servir de guia. Com usort é uma linha.

A ordenação em uma linha

$itens = [
    ['nome' => 'Camiseta', 'preco' => 79.90, 'destaque' => 0],
    ['nome' => 'Boné',     'preco' => 39.90, 'destaque' => 1],
    ['nome' => 'Tênis',    'preco' => 259.00, 'destaque' => 0],
];

usort($itens, fn(array $a, array $b) => $a['preco'] <=> $b['preco']);

O operador spaceship devolve -1, 0 ou 1 comparando os dois valores, que é exatamente o contrato que o usort espera da função de comparação. E desde o PHP 8.0 a ordenação é estável: itens com o mesmo preço mantêm a ordem em que apareceram no array. Antes disso a ordem deles variava entre versões.

Ordenar por dois campos

Para colocar os destaques na frente e, dentro de cada grupo, ordenar por preço crescente, compare arrays. O PHP compara elemento por elemento, da esquerda pra direita, e só passa pro próximo em caso de empate.

usort($itens, function (array $a, array $b) {
    return [$b['destaque'], $a['preco']] <=> [$a['destaque'], $b['preco']];
});

A pegadinha do retorno booleano

Escrever return $a['preco'] > $b['preco']; parece funcionar, mas o PHP 8 solta Deprecated: usort(): Returning bool from comparison function is deprecated. O motivo é que false serve tanto pra “menor” quanto pra “igual” e o motor não consegue separar os dois casos. O outro erro clássico é subtrair preços com casas decimais: o retorno vira int, 79.90 menos 79.50 dá 0 e os dois passam por empate. Use o spaceship.

Última coisa: usort reindexa as chaves de 0 em diante. Se as chaves do array significam alguma coisa, troque por uasort, que ordena preservando a associação entre chave e valor.

Post Recentes

Criar cupom no WooCommerce por código: WC_Coupon com validade e limite

Função pronta para gerar um cupom único por cliente depois do pedido concluído, com WC_Coupon, data de expiração, limite de…

13 horas atrás

Modifier de produto no Magento 2: campo novo no form sem sobrescrever XML

Como registrar um modifier no pool do formulário de produto do Magento 2 e criar um campo próprio na aba,…

1 dia atrás

Tela branca no WordPress 6.9: como achar o erro com PHP 8.3

Site abrindo em branco sem mensagem nenhuma? Leia o log do PHP-FPM, identifique o plugin que causou o fatal e…

2 dias atrás

DateTimeImmutable modify: por que a data não muda no PHP 8.3

Trocou DateTime por DateTimeImmutable e a data parou de andar? O modify devolve uma cópia nova em vez de alterar…

3 dias atrás

Defer nos scripts do WordPress 6.9 sem plugin, com wp_enqueue_script

Use o parâmetro strategy do wp_enqueue_script para adiar o JavaScript do tema, sem plugin de otimização, e entenda por que…

4 dias atrás

Banner de cookie que bloqueia de verdade: script só carrega depois do aceite

O banner aparece, o visitante não clica em nada e o Analytics já gravou cookie. Veja como segurar o script…

4 dias atrás