PHP 8

str_contains no PHP 8: parar de comparar strpos com !== false

Código cheio de strpos comparado com !== false é herança de PHP 5. O PHP 8 trouxe str_contains, str_starts_with e str_ends_with: devolvem bool de verdade e acabam com o esquecimento clássico do !== que transforma posição zero em falso.

Antes e depois

// PHP 7.4
if (strpos($ua, 'Googlebot') !== false) { ... }
if (substr($rota, 0, 7) === '/admin/') { ... }
if (substr($arquivo, -5) === '.webp') { ... }

// PHP 8.3
if (str_contains($ua, 'Googlebot')) { ... }
if (str_starts_with($rota, '/admin/')) { ... }
if (str_ends_with($arquivo, '.webp')) { ... }

O bug que sempre aparece em revisão de código é if (strpos($rota, ‘/admin/’)) sem comparação nenhuma. Quando a agulha está no começo da string, strpos devolve 0, o if trata como falso e a regra some. Com str_starts_with isso não tem como acontecer.

As três são sensíveis a maiúsculas, igual strpos. Se o trecho antigo usava stripos, trocar direto por str_contains muda o comportamento: aí é str_contains(strtolower($a), strtolower($b)), ou mb_strtolower quando tem acento no meio.

Ainda tem servidor no 7.4?

Em projeto legado que roda em várias hospedagens eu escrevo o código novo e carrego o polyfill cedo, antes de qualquer coisa que use as funções:

if (!function_exists('str_contains')) {
    function str_contains(string $palheiro, string $agulha): bool {
        return $agulha === '' || strpos($palheiro, $agulha) !== false;
    }
}

Se o projeto usa Composer, prefira o pacote symfony/polyfill-php80: cobre as três funções de uma vez e sai de cena sozinho quando o servidor sobe de versão.

Um detalhe do comportamento com agulha vazia: str_contains($texto, ”) devolve true sempre, e str_starts_with também. Se você monta o termo a partir de um campo de busca que pode chegar em branco, valide antes, senão o filtro deixa passar a lista inteira.

Um grep por “!== false” no projeto costuma render uma limpeza rápida e sem risco de regressão.

Post Recentes

Prompt injection em campo de usuário: isole a observação do pedido

A observação do pedido chegou com ordem embutida para gerar cupom. Delimite o texto do cliente e trate a resposta…

9 horas atrás

Preço promocional em massa no WooCommerce: agendar a Black Friday pelo WP-CLI

Um CSV com SKU e preço, um wp eval-file que agenda início e fim da promoção guardando o estado anterior,…

15 horas atrás

Too many connections no MySQL: achar quem segura as conexões antes de subir o limite

O erro 1040 aparece quando todas as conexões estão ocupadas. Antes de subir o max_connections, veja quem está segurando cada…

1 dia atrás

WP_MEMORY_LIMIT no WordPress: resolver memória esgotada no PHP 8.3

Allowed memory size exhausted no painel: qual das duas constantes do wp-config.php mexer, onde conferir o valor real e por…

2 dias atrás

Converter data dd/mm/aaaa para o MySQL com DateTime::createFromFormat

strtotime com data brasileira devolve false e o INSERT quebra no MySQL 8. Use createFromFormat com getLastErrors antes de mandar…

4 dias atrás

Erro 500 no Magento 2: achar o relatório em var/report pelo ID da tela

O hash que o Magento mostra junto do erro é o nome de um arquivo em var/report. Veja como abrir,…

5 dias atrás