Esto ocurre porque, como dice la nota en el Manual de PHP:
strlen()
devuelve el número de bytes en lugar del número de
caracteres de un string.
Debido a la ñ
, tu cadena tiene 5 bytes, no 4.
Otras soluciones son posibles:
Tres posibilidades
Sólo que en muchas instalaciones de PHP no existe. Y puede que haga falta instalarlo previamente:
<?php
$pal="niño";
$long=mb_strlen($pal);
echo $long;
?>
2. Usar una expresión regular
<?php
$pal="niño";
$long = preg_match_all( '(.)su', $pal, $matches );
echo $long;
?>
3. Decodificar la cadena
<?php
$pal="niño";
$long = strlen( utf8_decode( $pal ) );
echo $long;
?>
Caso curioso: leer por caracteres
Curiosamente, si se intenta leer la cadena como si fuera un array, caracter por caracter, queda demostrado que la codificación no aplica de manera interna a los elementos del array.
Según se explica en este artículo, para hacer esto es preciso crear una función propia que maneje los caracteres multibyte de la cadena:
function mb_str_split($str) {
// split multibyte string in characters
// Split at all positions, not after the start: ^
// and not before the end: $
$pattern = '/(?<!^)(?!$)/u';
return preg_split($pattern,$str);
}
Ayudándonos de esa función sí es posible imprimir bien los caracteres. Entonces el código quedaría así:
$arrPal = mb_str_split($pal);//str_split($pal,4);
for($i=0;$i<$long;$i++){
echo " $arrPal[$i] ";
}
O, podemos usar un for mejorado:
foreach ($arrPal as $char) {
echo $char;
}
En ambos casos la salida sería correcta.
Es curioso e interesante lo que ocurre aquí y sería bueno quizá plantearlo como una pregunta independiente.