Une chaîne numérique comme clé de tableau en PHP

104

Est-il possible d'utiliser une chaîne numérique comme "123"une clé dans un tableau PHP, sans qu'elle soit convertie en entier?

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

impressions

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

Je voudrais

array(1) {
  ["123"]=>
  int(1)
}
Dogbert
la source
7
Puisque PHP est mal typé, "123"== 123pour presque tous les usages. Quelle est la raison pour laquelle vous le voulez spécifiquement sous forme de chaîne (et avoir un int est mauvais)?
ircmaxell
17
La raison qui me vient à l'esprit concerne les fonctions de tableau comme array_merge "Si les tableaux d'entrée ont les mêmes clés de chaîne, la valeur la plus récente de cette clé écrasera la précédente. Si, cependant, les tableaux contiennent des clés numériques , la valeur la plus récente ne sera pas écraser la valeur d'origine, mais sera ajoutée. "
ficuscr
8
Un autre exemple où les chaînes numériques en tant que clés de tableau est problématique:asort
swenedo
4
Un autre cas d'utilisation: le test unitaire de la transition de données JSON. La conversion d'un tel tableau en JSON et inversement ne vous permettra pas d'affirmer que l'original et le résultat sont exactement les mêmes.
David le

Réponses:

90

Non; non ce n'est pas:

À partir du manuel :

Une clé peut être un entier ou une chaîne. Si une clé est la représentation standard d'un entier, elle sera interprétée comme telle (c'est-à-dire que "8" sera interprété comme 8, tandis que "08" sera interprété comme "08").

Addenda

À cause des commentaires ci-dessous, j'ai pensé qu'il serait amusant de souligner que le comportement est similaire mais pas identique aux clés d'objet JavaScript.

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

foo['10']; // "bar"
foo[10]; // "bar"
foo[012]; // "bar"
foo['012']; // undefined!
Hamish
la source
107
PHP, l'IE côté serveur.
Marek Maurizio
5
On dirait qu'il y a un moyen, en fait! Êtes-vous en désaccord avec cette réponse? stackoverflow.com/a/35180513/247696
Flimm
1
Comment?! .. foo [012] return "bar"
Himanshu
2
@Himanshu: parce que php interprète les nombres commençant par 0 comme octal. donc 012 est octal 10.
Yeasir Arafat Majumder
49

Oui, c'est possible en transtypant un stdClassobjet en tableau :

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

Cela vous donne (jusqu'à la version 7.1 de PHP):

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

(Mise à jour: Ma réponse originale montrait une manière plus compliquée en utilisant json_decode()et json_encode()qui n'est pas nécessaire.)

Notez le commentaire : Il n'est malheureusement pas possible de référencer directement la valeur: $data['12']entraînera un avis.

Mise à jour : à
partir de PHP 7.2, il est également possible d'utiliser une chaîne numérique comme clé pour référencer la valeur:

var_dump( $data['12'] ); // int 32
David
la source
2
L'accès direct à la valeur avec une clé de chaîne ne fonctionne pas, cependant. Ajouter cette ligne à votre exemple: echo $data['12'];. Il donnera l'erreur, "Avis: Décalage non défini: 12 pouces - sur la ligne 5".
LS
Oui tu as raison. En supposant que c'était parfois possible dans le passé.
David
1
quand U utilise laravel dd ($ data) il plantera: P
Kamil Kiełczewski
2
En PHP 7.2.0RC2, le comportement est le même qu'avant.
dev0
1
Apparemment, array_key_existsje ne le trouverai pas non plus dans les anciennes versions.
Don't Panic
12

Si vous avez besoin d'utiliser une clé numérique dans une structure de données php, un objet fonctionnera. Et les objets préservent l'ordre, vous pouvez donc itérer.

$obj = new stdClass();
$key = '3';
$obj->$key = 'abc';
à vapeur
la source
C'est une très bonne suggestion. J'écris du code de cadre et je suis confronté à quelqu'un qui passe un tableau qui pourrait avoir soit une indexation "accidentelle": array ('this', 'that') ou une indexation "associative": array (123 => array ('this', 'that ')). Maintenant, grâce à vous, je peux simplement taper un indice;) +1
Just Plain High
Mais est-il possible d'utiliser une chaîne numérique comme "123" comme clé dans un tableau PHP, sans qu'elle soit convertie en entier?
Flimm
@Flimm non ce n'est pas possible, c'est pourquoi je propose ma solution.
alimenté à vapeur le
@Flimm cette réponse semble contredire le manuel PHP : Les chaînes contenant des entiers valides seront converties en type entier. Par exemple, la clé "8" sera en fait stockée sous 8. Par contre "08" ne sera pas converti, car ce n'est pas un entier décimal valide. , bien que je n’ai pas testé sa réponse.
vapeur le
Cette phrase se trouve dans la section "Spécifier avec array(), donc je suppose que dans ce contexte, les chaînes spécifiant des entiers valides seront converties en type entier. Mais il s'avère qu'il existe d'autres façons de créer des tableaux, là où cela ne se produit pas, comme dans la réponse de David, que j'ai testée.
Flimm
10

Ma solution de contournement est:

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

L'espace char (prefend) est une bonne solution car gardez la conversion int:

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

Vous verrez 55 comme int.

Undolog
la source
4
Ou "0$id" => $value. La préparation avec des 0œuvres aussi.
nawfal
Vous dites donc qu'il n'est pas possible d'utiliser une chaîne numérique comme "123" comme clé dans un tableau PHP, sans qu'elle soit convertie en entier?
Flimm
5

Vous pouvez taper la clé en chaîne, mais elle sera finalement convertie en un entier en raison de la saisie lâche de PHP. Voir par vous-même:

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

Depuis le manuel PHP:

Une clé peut être un entier ou une chaîne. Si une clé est la représentation standard d'un entier, elle sera interprétée comme telle (c'est-à-dire que "8" sera interprété comme 8, tandis que "08" sera interprété comme "08"). Les flottants dans la clé sont tronqués en nombre entier. Les types de tableaux indexés et associatifs sont du même type en PHP, qui peuvent à la fois contenir des indices entiers et chaînes.

bcosca
la source
1
La conversion n'est pas due à une saisie lâche; php détermine si la chaîne a l' air numérique, puis la convertit.
Ja͢ck
1
Alors tu dis que ce n'est pas possible? Cette réponse montre qu'il existe un moyen d'utiliser une chaîne qui ressemble à un entier comme clé dans un tableau.
Flimm
IMHO le problème est l'interpréteur PHP. Il n'est même pas possible d'imaginer un langage qui mélange des chaînes et des entiers en tant que clés de tableau. La meilleure solution? Comme proposé par Undolog stackoverflow.com/a/15413637/1977778, la meilleure solution est d'utiliser un espace de fin ... Malheureusement.
sentenza
@sentenza: Il est possible d'imaginer, d'autant plus que PHP permet un mélange de chaînes et d'entiers comme les clés d'un tableau:[42 => 'answer', 'snafu' => 'fubar']
LS
@LS oui. Je sais que PHP vous permet de le faire, mais si vous considérez les clés dans un système de type générique hypothétique, il ne correspondra à aucun type mixte qui englobe des chaînes et des nombres en même temps. Le typage lâche appliqué aux clés d'un tableau associatif est simplement sujet aux erreurs.
sentenza
1

J'ai eu ce problème en essayant de fusionner des tableaux qui avaient à la fois des clés de chaîne et des clés entières. Il était important que les entiers soient également traités comme des chaînes car il s'agissait de noms pour les champs de saisie (comme dans les pointures de chaussures, etc.)

Quand j'utilisais $data = array_merge($data, $extra);PHP, je réorganisais les clés. Dans une tentative de classement, les clés entières (j'ai essayé avec 6- '6'- "6"même en (string)"6"tant que clés) ont été renommées de 0 à n... Si vous y réfléchissez, dans la plupart des cas, ce serait le comportement souhaité.

Vous pouvez contourner ce problème en utilisant à la $data = $data + $extra;place. Assez simple, mais je n'y ai pas pensé au début ^^.

Brainfeeder
la source
Le même problème m'a conduit à cette page, mais je dois dire que ce n'est pas la réponse à la question d'OP.
Flimm
@Flimm True. Mais la recherche d'une réponse m'a conduit à cette page. J'ai pensé que ma solution pourrait être une aide pour d'autres googleurs :)
Brainfeeder
1

Les chaînes contenant des entiers valides seront converties en type entier. Par exemple, la clé "8" sera en fait stockée sous 8. Par contre "08" ne sera pas converti, car ce n'est pas un entier décimal valide.

FAUX

J'ai une fonction de casting qui gère le casting séquentiel à associatif,

$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
la source
1

Pour contourner ce problème, vous pouvez encoder un tableau PHP en objet json, avec l'option JSON_FORCE_OBJECT.

ie, cet exemple:

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

aura pour résultat:

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

J'ai rencontré ce problème sur un tableau avec à la fois «0» et «» comme clés. Cela signifiait que je ne pouvais pas vérifier mes clés de tableau avec == ou ===.

$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 solution de contournement consiste à convertir les clés du tableau en chaînes avant utilisation.

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";
    }
}
meilleur fishare
la source
1
Ce n'est pas vraiment une réponse à la question.
Flimm
0

En ce qui concerne la solution @david, veuillez noter que lorsque vous essayez d'accéder aux valeurs de chaîne dans le tableau associatif, les nombres ne fonctionneront pas. Je suppose qu'ils sont convertis en nombres entiers dans les coulisses (lors de l'accès au tableau) et qu'aucune valeur n'est trouvée. L'accès aux valeurs sous forme d'entiers ne fonctionnera pas non plus. Mais vous pouvez utiliser array_shift () pour obtenir les valeurs ou parcourir le tableau.

$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
la source
Quelle version de php? J'ai essayé exactement votre exemple et la clé "0"devient 0avec php 7.2.10.
J.BizMai
-1

J'ai eu ce problème en essayant de trier un tableau où j'avais besoin que la clé de tri soit un hex sha1. Lorsqu'une valeur sha1 résultante n'a pas de lettres, PHP transforme la clé en un entier. Mais j'avais besoin de trier le tableau dans l'ordre relatif des chaînes. J'avais donc besoin de trouver un moyen de forcer la clé à être une chaîne sans changer l'ordre de tri.

En regardant le graphique ASCII ( https://en.wikipedia.org/wiki/ASCII ), le point d'exclamation est à peu près identique à l'espace et certainement inférieur à tous les chiffres et lettres.

J'ai donc ajouté un point d'exclamation à la fin de la chaîne de clé.

for(...) {

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

ksort($database);
$row = reset($database);
$topsha = $row[0];
drchuck
la source
Alors, dites-vous qu'il n'est pas possible d'utiliser une chaîne numérique comme "123" comme clé dans un tableau PHP, sans qu'elle soit convertie en entier?
Flimm
Non - il ne traite que la clé qui contient tous les nombres comme un entier lors du tri du tableau à l'aide de ksort () - il n'est jamais converti en un entier - juste comparé à un pendant le tri.
drchuck