Una cadena numérica como clave de matriz en PHP

104

¿Es posible usar una cadena numérica "123"como una clave en una matriz de PHP, sin que se convierta en un número entero?

$blah = array('123' => 1);
var_dump($blah);

huellas dactilares

array(1) {
  [123]=>
  int(1)
}

quiero

array(1) {
  ["123"]=>
  int(1)
}
Dogbert
fuente
7
Dado que PHP se escribe libremente, "123"== 123para casi todos los propósitos. ¿Cuál es la razón por la que lo quiere específicamente como una cadena (y tener un int es malo)?
ircmaxell
17
La razón que me viene a la mente se relaciona con funciones de matriz como array_merge "Si las matrices de entrada tienen las mismas claves de cadena, entonces el valor posterior de esa clave sobrescribirá al anterior. Sin embargo, si las matrices contienen claves numéricas , el valor posterior no sobrescribe el valor original, pero se agregará ".
Ficuscr
8
Otro ejemplo en el que las cadenas numéricas como claves de matriz es problemática:asort
swenedo
4
Otro caso de uso: transición de datos JSON de pruebas unitarias. Convertir una matriz de este tipo a JSON y viceversa no le permitirá afirmar que tanto el original como el resultado son exactamente iguales.
David

Respuestas:

90

No; no, no es:

Del manual :

Una clave puede ser un número entero o una cadena. Si una clave es la representación estándar de un número entero, se interpretará como tal (es decir, "8" se interpretará como 8, mientras que "08" se interpretará como "08").

Apéndice

Debido a los comentarios a continuación, pensé que sería divertido señalar que el comportamiento es similar pero no idéntico a las claves de objetos de JavaScript.

foo = { '10' : 'bar' };

foo['10']; // "bar"
foo[10]; // "bar"
foo[012]; // "bar"
foo['012']; // undefined!
Hamish
fuente
107
PHP, el IE del lado del servidor.
Marek Maurizio
5
¡Parece que hay una manera, en realidad! ¿No está de acuerdo con esta respuesta? stackoverflow.com/a/35180513/247696
Flimm
1
¿Cómo?! .. foo [012] return "bar"
Himanshu
2
@Himanshu: porque php interpreta los números que comienzan con 0 como octal. entonces 012 es 10 octal.
Yeasir Arafat Majumder
49

Sí, es posible mediante la conversión de matriz de un stdClassobjeto:

$data =  new stdClass;
$data->{"12"} = 37;
$data = (array) $data;
var_dump( $data );

Eso le da (hasta PHP versión 7.1):

array(1) {
  ["12"]=>
  int(37)
}

(Actualización: mi respuesta original mostró una forma más complicada de usar json_decode()y json_encode()que no es necesaria).

Tenga en cuenta el comentario : Desafortunadamente, no es posible hacer referencia al valor directamente: $data['12']resultará en un aviso.

Actualización :
desde PHP 7.2 en adelante, también es posible usar una cadena numérica como clave para hacer referencia al valor:

var_dump( $data['12'] ); // int 32
David
fuente
2
Sin embargo, el acceso directo al valor con una clave de cadena no funciona. Agregue esta línea a su ejemplo:echo $data['12']; . Dará el error, "Aviso: Desplazamiento indefinido: 12 en - en la línea 5".
LS
1
cuando U use laravel dd ($ data) se bloqueará: P
Kamil Kiełczewski
2
En PHP 7.2.0RC2 el comportamiento es el mismo que antes.
dev0
1
Aparentemente array_key_existstampoco lo encontrará en las versiones anteriores.
Que no cunda el pánico
1
no funciona en php 7.4
jazmines
12

Si necesita usar una clave numérica en una estructura de datos php, un objeto funcionará. Y los objetos conservan el orden, por lo que puede iterar.

$obj = new stdClass();
$key = '3';
$obj->$key = 'abc';
vapor accionado
fuente
Esta es una muy buena sugerencia. Estoy escribiendo código de marco y me enfrento a alguien que pasa una matriz que podría tener indexación "accidental": matriz ('esto', 'eso') o indexación "asociativa": matriz (123 => matriz ('esto', 'eso ')). Ahora, gracias a ti, puedo escribir una sugerencia;) +1
Just Plain High
Pero, ¿es posible utilizar una cadena numérica como "123" como clave en una matriz PHP, sin que se convierta en un número entero?
Flimm
@Flimm no, eso no es posible, por eso ofrezco mi solución.
Vaporizado el
@Flimm esa respuesta parece contradecir el manual de PHP : las cadenas que contienen enteros válidos se convertirán al tipo de entero. Por ejemplo, la clave "8" se almacenará en realidad en 8. Por otro lado, "08" no se convertirá, ya que no es un entero decimal válido. , aunque no he probado su respuesta.
Vaporizado el
Esa oración se encuentra en la sección "Especificar con array(), por lo que supongo que en ese contexto las cadenas que especifican números enteros válidos se convertirán en el tipo de número entero. Pero resulta que hay otras formas de crear matrices, donde eso no sucede, como en la respuesta de David, que he probado.
Flimm
10

Mi solución es:

$id = 55;
$array = array(
  " $id" => $value
);

El espacio char (anteponer) es una buena solución porque mantiene la conversión int:

foreach( $array as $key => $value ) {
  echo $key;
}

Verás 55 como int.

Undolog
fuente
4
O "0$id" => $value. Anteponer con 0obras también.
Nawfal
Entonces, ¿estás diciendo que no es posible usar una cadena numérica como "123" como clave en una matriz PHP, sin que se convierta en un número entero?
Flimm
5

Puede encasillar la clave en una cadena, pero eventualmente se convertirá en un número entero debido a la escritura suelta de PHP. Ver por ti mismo:

$x=array((string)123=>'abc');
var_dump($x);
$x[123]='def';
var_dump($x);

Del manual de PHP:

Una clave puede ser un número entero o una cadena. Si una clave es la representación estándar de un número entero, se interpretará como tal (es decir, "8" se interpretará como 8, mientras que "08" se interpretará como "08"). Los flotantes en clave se truncan a un número entero. Los tipos de matrices indexadas y asociativas son del mismo tipo en PHP, que pueden contener índices enteros y de cadena.

bcosca
fuente
1
La conversión no se debe a una escritura suelta; php determina si la cadena se ve numérica y luego la convierte.
Ja͢ck
1
Entonces, ¿estás diciendo que no es posible? Esta respuesta muestra que hay una forma de usar una cadena que parece un número entero como clave en una matriz.
Flimm
En mi humilde opinión, el problema es el intérprete de PHP. Ni siquiera es posible imaginar tener un lenguaje que mezcle cadenas y números enteros como claves de matriz. ¿La mejor solucion? Según lo propuesto por Undolog stackoverflow.com/a/15413637/1977778, la mejor solución es usar un espacio final ... Lamentablemente.
sentencia
@sentenza: Se es posible imaginar, sobre todo a partir de PHP permite una mezcla de palabras y enteros como las claves de una matriz:[42 => 'answer', 'snafu' => 'fubar']
LS
@LS sí. Sé que PHP le permite hacerlo, pero si considera las claves dentro de un sistema hipotético de tipos genéricos, no coincidirá con ningún tipo mixto que abarque cadenas y números al mismo tiempo. La escritura suelta aplicada a las claves de una matriz asociativa es simplemente propensa a errores.
sentencia
1

Tuve este problema al intentar fusionar matrices que tenían claves de cadena y enteras. Era importante que los enteros también se manejaran como cadenas, ya que eran nombres para campos de entrada (como en tallas de zapatos, etc.)

Cuando usé $data = array_merge($data, $extra);PHP, 'reordenaría' las claves. En un intento de ordenar, las claves enteras (lo intenté con 6- '6'- "6"incluso (string)"6"como claves) se renombraron de 0 a n... Si lo piensa, en la mayoría de los casos este sería el comportamiento deseado.

Puede solucionar este problema utilizando en su $data = $data + $extra;lugar. Bastante sencillo, pero no pensé en eso al principio ^^.

Brainfeeder
fuente
Exactamente el mismo problema me llevó a esta página, pero debo decir que esta no es la respuesta a la pregunta de OP.
Flimm
@Flimm True. Pero la búsqueda de una respuesta me llevó a esta página. Pensé que mi solución podría ser de ayuda para otros empleados de Google :)
Brainfeeder
1

Las cadenas que contienen enteros válidos se convertirán al tipo de entero. Por ejemplo, la clave "8" se almacenará en realidad en 8. Por otro lado, "08" no se convertirá, ya que no es un entero decimal válido.

INCORRECTO

Tengo una función de conversión que maneja la conversión de matrices secuenciales a asociativas,

$array_assoc = cast($arr,'array_assoc');

$array_sequential = cast($arr,'array_sequential');

$obj = cast($arr,'object');

$json = cast($arr,'json');



function cast($var, $type){

    $orig_type = gettype($var);

    if($orig_type == 'string'){

        if($type == 'object'){
            $temp = json_decode($var);
        } else if($type == 'array'){
            $temp = json_decode($var, true);
        }
        if(isset($temp) && json_last_error() == JSON_ERROR_NONE){
            return $temp;
        }
    }
    if(@settype($var, $type)){
        return $var;
    }
    switch( $orig_type ) {

        case 'array' :

            if($type == 'array_assoc'){

                $obj = new stdClass;
                foreach($var as $key => $value){
                    $obj->{$key} = $value;
                }
                return (array) $obj;

            } else if($type == 'array_sequential'){

                return array_values($var);

            } else if($type == 'json'){

                return json_encode($var);
            }
        break;
    }
    return null; // or trigger_error
}
TarranJones
fuente
no funciona en php 7.4
jazmines
1

Como solución alternativa, puede codificar la matriz PHP en un objeto json, con la opción JSON_FORCE_OBJECT.

es decir, este ejemplo:

     $a = array('foo','bar','baz');
     echo "RESULT: ", json_encode($a, JSON_FORCE_OBJECT);

resultará en:

     RESULT: {"0" : "foo", "1": "bar", "2" : "baz"}
GigiManco
fuente
0

Me encontré con este problema en una matriz con '0' y '' como claves. Significaba que no podía verificar mis claves de matriz con == o ===.

$array=array(''=>'empty', '0'=>'zero', '1'=>'one');
echo "Test 1\n";
foreach ($array as $key=>$value) {
    if ($key == '') { // Error - wrongly finds '0' as well
        echo "$value\n";
    }
}
echo "Test 2\n";
foreach ($array as $key=>$value) {
    if ($key === '0') { // Error - doesn't find '0'
        echo "$value\n";
    }
}

La solución es convertir las claves de matriz de nuevo en cadenas antes de su uso.

echo "Test 3\n";
foreach ($array as $key=>$value) {
    if ((string)$key == '') { // Cast back to string - fixes problem
        echo "$value\n";
    }
}
echo "Test 4\n";
foreach ($array as $key=>$value) {
    if ((string)$key === '0') { // Cast back to string - fixes problem
        echo "$value\n";
    }
}
fisharebest
fuente
1
Esta no es realmente una respuesta a la pregunta.
Flimm
0

Con respecto a la solución @david, tenga en cuenta que cuando intente acceder a los valores de cadena en la matriz asociativa, los números no funcionarán. Supongo que se convierten en números enteros detrás de escena (al acceder a la matriz) y no se encuentra ningún valor. Acceder a los valores como números enteros tampoco funcionará. Pero puede usar array_shift () para obtener los valores o iterar la matriz.

$data = new stdClass;
$data->{"0"} = "Zero";
$data->{"1"} = "One";
$data->{"A"} = "A";
$data->{"B"} = "B";

$data = (array)$data;

var_dump($data);
/*
Note the key "0" is correctly saved as a string:
array(3) {
  ["0"]=>
  string(4) "Zero"
  ["A"]=>
  string(1) "A"
  ["B"]=>
  string(1) "B"
}
*/

//Now let's access the associative array via the values 
//given from var_dump() above:
var_dump($data["0"]); // NULL -> Expected string(1) "0"
var_dump($data[0]); // NULL (as expected)
var_dump($data["1"]); // NULL -> Expected string(1) "1"
var_dump($data[1]); // NULL (as expected)
var_dump($data["A"]); // string(1) "A" (as expected)
var_dump($data["B"]); // string(1) "B" (as expected)
Nico Schefer
fuente
¿Qué versión de php? Probé exactamente tu ejemplo y la clave se "0"convierte 0en php 7.2.10.
J.BizMai
-1

Tuve este problema al intentar ordenar una matriz donde necesitaba que la clave de clasificación fuera un hex sha1. Cuando un valor sha1 resultante no tiene letras, PHP convierte la clave en un número entero. Pero necesitaba ordenar la matriz según el orden relativo de las cadenas. Así que necesitaba encontrar una manera de forzar que la clave fuera una cadena sin cambiar el orden de clasificación.

Mirando la tabla ASCII ( https://en.wikipedia.org/wiki/ASCII ), el signo de exclamación se ordena casi igual que el espacio y ciertamente más bajo que todos los números y letras.

Así que agregué un signo de exclamación al final de la cadena de teclas.

for(...) {

    $database[$sha.'!'] = array($sha,$name,$age);
}

ksort($database);
$row = reset($database);
$topsha = $row[0];
drchuck
fuente
Entonces, ¿estás diciendo que no es posible usar una cadena numérica como "123" como clave en una matriz PHP, sin que se convierta en un número entero?
Flimm
No, solo trata la clave que son todos los números como un entero al ordenar la matriz usando ksort (); nunca se convierte en un número entero, solo se compara como uno durante la clasificación.
drchuck