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)
}

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!

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

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';

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.


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.


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 ^^.


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
}

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"}

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";
    }
}

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)

¿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];

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.