Las matrices en PHP, más conocidas como arrays, se construyen mediante pares clave => valor que representan cada elemento de la matriz. En función del tipo de clave, o key, el array puede ser:

  • asociativo: la clave es un string, un texto identificador, por ejemplo $array['nombre'], $array['edad'], etc.
  • secuencial: la clave es un índice numérico, de ahí que este tipo de arrays también se conozcan como arrays indexados, por ejemplo, $array[1], $array[2], etc.

La representación interna en PHP de ambos tipos de arrays es la misma, un mapa con un orden específico con claves y valores asociados, pero, aún así, en algunas situaciones podemos necesitar conocer si estamos ante uno u otro tipo.

PHP ofrece varias funciones internas para comprobar el tipo de datos pero ninguna para diferenciar arrays secuenciales y asociativos, pero podemos hacerlo nosotros.

Uno de los métodos más populares y sencillos se basa en comparar las keys de un array con el resultado que de la función range() desde 0 al número de elementos del array.

function is_assoc( $array ) {
	return array_keys( $array ) !== range( 0, count($array) - 1 );
}

Supongamos que un array tiene 5 elementos. El plantemiento anterior sería: si range(0, 4) me devuelve el mismo valor que array_keys($array), estaré ante un array secuencial, de lo contrario estoy ante un array asociativo (vea manual de range() y array_keys()).

Problema

Las claves en un array secuencial generalmente van desde 0 (cero) hasta el número de elementos menos 1. Esto es así si no se especifican los índices, si se especifican con esos valores o si la clave es igual al valor del elemento:

// Los tres arrays son secuenciales
// y se consideran iguales en PHP
$datos = array(
            "Gato",
            "Perro",
            "Jirafa"
        );
$datos = array(
            0 => "Gato",
            1 => "Perro",
            2 => "Jirafa"
        );
$datos = array(
            "Gato" => "Gato",
            "Perro" => "Perro",
            "Jirafa" => "Jirafa"
        );

Los tres arrays anteriores son iguales, se consideran secuenciales, sus claves son 0, 1 y 2, y se puede acceder al valor de cada elemento mediante $datos[indice], donde índice es el número que representa el key.

Pero, como podemos especificar el número de índice a nuestro antojo, ¿que pasa si el key menor no es 0? (2, 3, 4, …) ¿Y si hay “huecos”? (2, 8, 54,…). En estos casos la solución propuesta con range() y array_keys() tratará los datos como array asociativo y para muchos programadores estos arrays son secuenciales.

No hay una definición estándar de array secuencial; para algunos, un array en el que todas las claves son números enteros, aunque no comiencen por cero o no sigan la secuencia +1, es un array secuencial; para otros, un array secuencial en el que la clave es importante en sí misma, se convierte automáticametne en array asociativo aunque todas claves sean numéricas, cosa que ocurriría con arrays en el que las clvaves numéricas presentan “huecos” de una a otra.

Además, en PHP las claves tipo string que contienen representación literal de enteros son convertidas a datos tipo integer; por ejemplo la clave "8" (string) es convertida a 8 (integer), pero "08" si es tratado como string y no es convertido a 8. Lo mismo ocurre con keys tipo float ( por ejemplo 8.5) que son transformadas a integer (8).

En otras palabras, en PHP no puedes diferenciar el key "8" (texto) del key 8 (número). (vea la documentación sobre arrays).

No voy a entrar en como defino yo cada tipo de array, sería entrar en un debate eterno, pero si quieres interpretar como secuencial cualquier array cuyas claves sean todas números enteros, sin importar que la menor no sea cero o que haya huecos entre ellas, puedes utilizar el siguiente código:

function is_assoc($array) {

     foreach(array_keys($array) as $key) {
         if (!is_int($key)) return true;
     }

     return false;

}

La función anterior comprueba cada una de las claves del array hasta que encuentre una que no sea un número entero; sólo en ese caso devolverá true, indicando que el array es asociativo. En caso contrario devolverá false, indicando que el array es secuencial o indexado.