strlen($string) retorna o tamanho de uma string em bytes. Para caracteres, que é o que você quer para texto japonês, letras acentuadas e emoji, use mb_strlen($string). Para texto simples em inglês, os dois dão o mesmo número.
Espaços, pontuação e quebras de linha contam. strlen("a b\n") é 4.
Bytes e caracteres em UTF-8
Strings PHP são sequências de bytes, e o UTF-8 usa um número diferente de bytes por caractere: 1 para letras e dígitos ASCII, 2 para letras como é ou ж, 3 para kana, kanji comuns, caracteres chineses e símbolos como €, e 4 para a maioria dos emoji e kanji raros como 𠮷. O strlen() soma os bytes; o mb_strlen() conta os caracteres.
Use strlen() quando os bytes importam: uma coluna do banco limitada em bytes, o tamanho de um arquivo, um protocolo binário. Use mb_strlen() para tudo o que uma pessoa lê: um contador de caracteres, uma regra de "no máximo 20 caracteres", cortar texto com mb_substr().
Emoji e caracteres formados por vários code points
O mb_strlen() conta code points Unicode. Algumas coisas que um leitor vê como um caractere são vários code points juntos: um emoji de família, uma bandeira, um tom de pele, ou uma letra mais um acento combinado.
Contar o que um leitor vê como caracteres únicos (grapheme clusters) exige o grapheme_strlen() da extensão intl:
echo grapheme_strlen('👨👩👧'); // 1
echo grapheme_strlen('🇯🇵'); // 1
Para um contador de caracteres num formulário em japonês, o mb_strlen() normalmente basta: cada kana e cada kanji é um único code point.
Largura de exibição com mb_strwidth
Num terminal ou num layout de largura fixa, um caractere japonês de largura total ocupa duas colunas, enquanto um katakana de meia largura ou uma letra latina ocupa uma. O mb_strwidth() retorna essa largura, que é o que as regras japonesas do tipo "全角は2文字" normalmente querem dizer.
Verificar se uma string está vazia
O teste mais claro é uma comparação estrita com ''. strlen($s) === 0 dá a mesma resposta. empty($s) não é a mesma coisa: ele também retorna true para a string "0", que é uma resposta válida em muitos formulários.
Uma string de espaços não é vazia. Passe-a antes pelo trim() se só espaços devem contar como nada.
strlen(null) e valores que não são string
O strlen() espera uma string. Passar null ainda retorna 0, mas desde o PHP 8.1 imprime um aviso de depreciação:
Deprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated in /home/index.php on line 2
Um array lança TypeError: strlen(): Argument #1 ($string) must be of type string, array given.
Faça um cast ou dê um padrão ao valor antes, por exemplo strlen($value ?? ''). Inteiros são convertidos em strings, então strlen(12345) é 5. Para contar elementos de um array, use count().
Validar o tamanho de uma entrada do usuário
Uma regra típica: um nome de usuário de 3 a 16 caracteres, depois do trim. Use mb_strlen() para que um nome japonês seja medido em caracteres, não em bytes.
Com strlen() no lugar de mb_strlen(), やまだたろう contaria como 18 e seria rejeitado como longo demais, mesmo tendo seis caracteres.
Perguntas frequentes
Como obtenho o tamanho de uma string no PHP?
strlen($s) retorna o número de bytes e mb_strlen($s) o número de caracteres. Para texto simples em inglês eles são iguais; para japonês, letras acentuadas ou emoji, use mb_strlen().
Por que o strlen() retorna o tamanho errado para texto japonês?
Não está errado, ele conta bytes. O UTF-8 guarda kana e kanji comuns em 3 bytes cada, então strlen('日本語') é 9 enquanto mb_strlen('日本語') é 3.
Como conto os caracteres de uma string com emoji?
O mb_strlen() conta code points Unicode, então um emoji simples conta como 1, mas um emoji formado por vários code points (uma família, uma bandeira, um tom de pele) conta como mais. O grapheme_strlen() da extensão intl conta o que um leitor vê como um caractere.
Qual a diferença entre strlen e count no PHP?
O strlen() mede uma string, o count() conta os elementos de um array. Passar um array para o strlen() lança um TypeError no PHP 8.
Como verifico se uma string está vazia no PHP?
Compare com uma string vazia: $s === '', ou strlen($s) === 0. Evite empty($s) para isso, porque ele também trata a string "0" como vazia.