Una stringa numerica come chiave di matrice in PHP


104

È possibile utilizzare una stringa numerica "123"come una chiave in un array PHP, senza che venga convertita in un numero intero?

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

stampe

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

Voglio

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

7
Poiché PHP è digitato in modo approssimativo , "123"== 123per quasi tutti gli scopi. Qual è il motivo per cui lo vuoi specificamente come stringa (e avere un int non è corretto)?
ircmaxell

17
Il motivo che mi viene in mente è relativo a funzioni di array come array_merge "Se gli array di input hanno le stesse chiavi di stringa, il valore successivo di quella chiave sovrascriverà quello precedente. Se, tuttavia, gli array contengono chiavi numeriche , il valore successivo non lo farà sovrascrivi il valore originale, ma verrà aggiunto. "
ficuscr

8
Un altro esempio in cui le stringhe numeriche come chiavi di array sono problematiche:asort
swenedo


4
Un altro caso d'uso: unit test di transizione dei dati JSON. La conversione di un tale array in JSON e viceversa non ti consentirà di affermare che sia l'originale che il risultato sono esattamente gli stessi.
David

Risposte:


90

No; no non lo è:

Dal manuale :

Una chiave può essere un numero intero o una stringa. Se una chiave è la rappresentazione standard di un numero intero, verrà interpretata come tale (cioè "8" sarà interpretato come 8, mentre "08" sarà interpretato come "08").

appendice

A causa dei commenti seguenti, ho pensato che sarebbe stato divertente sottolineare che il comportamento è simile ma non identico alle chiavi dell'oggetto JavaScript.

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

foo['10']; // "bar"
foo[10]; // "bar"
foo[012]; // "bar"
foo['012']; // undefined!

107
PHP, IE lato server.
Marek Maurizio

5
Sembra che ci sia un modo, in realtà! Non sei d'accordo con questa risposta? stackoverflow.com/a/35180513/247696
Flimm

1
Come?! .. foo [012] return "bar"
Himanshu

2
@Himanshu: perché php interpreta i numeri che iniziano con 0 come ottali. quindi 012 è ottale 10.
Yeasir Arafat Majumder il

49

Sì, è possibile eseguire il cast di un stdClassoggetto in array :

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

Questo ti dà (fino alla versione 7.1 di PHP):

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

(Aggiornamento: la mia risposta originale mostrava un modo più complicato di usare json_decode()e json_encode()che non è necessario.)

Nota il commento : purtroppo non è possibile fare riferimento direttamente al valore: $data['12']verrà visualizzato un avviso.

Aggiornamento :
da PHP 7.2 in poi è anche possibile utilizzare una stringa numerica come chiave per referenziare il valore:

var_dump( $data['12'] ); // int 32

2
Tuttavia, l'accesso diretto al valore con una chiave stringa non funziona. Aggiungere questa riga al tuo esempio: echo $data['12'];. Verrà visualizzato l'errore "Avviso: offset non definito: 12 in - sulla riga 5".
LS

Sì hai ragione. Supponendo che a volte fosse possibile in passato.
David

1
quando si usa laravel dd ($ data) andrà in crash: P
Kamil Kiełczewski

2
In PHP 7.2.0RC2 il comportamento è lo stesso di prima.
dev0

1
Apparentemente array_key_existsnon lo troverà nemmeno nelle versioni precedenti.
Niente panico

12

Se è necessario utilizzare una chiave numerica in una struttura dati php, un oggetto funzionerà. E gli oggetti mantengono l'ordine, quindi puoi iterare.

$obj = new stdClass();
$key = '3';
$obj->$key = 'abc';

Questo è un ottimo suggerimento. Sto scrivendo codice framework e mi trovo di fronte a qualcuno che passa un array che potrebbe avere indicizzazione "accidentale": array ('questo', 'quello') o indicizzazione "associativa": array (123 => array ('questo', 'quello ')). Ora, grazie a te, posso semplicemente scrivere un suggerimento;) +1
Semplicemente alto

Ma è possibile utilizzare una stringa numerica come "123" come chiave in un array PHP, senza che venga convertita in un numero intero?
Flimm

@Flimm no, non è possibile, motivo per cui offro la mia soluzione.
potenza del vapore

@Flimm questa risposta sembra contraddire il manuale PHP : le stringhe contenenti interi validi verranno convertite nel tipo intero. Ad esempio, la chiave "8" verrà effettivamente memorizzata sotto 8. D'altra parte "08" non verrà lanciato, poiché non è un numero intero decimale valido. , anche se non ho verificato la sua risposta.
potenza del vapore

Questa frase si trova nella sezione "Specificare con array(), quindi presumo che in quel contesto le stringhe che specificano interi validi verranno convertite nel tipo intero. Ma risulta che ci sono altri modi per creare array, dove ciò non accade, come nella risposta di David, che ho testato.
Flimm

10

La mia soluzione alternativa è:

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

Lo spazio char (prepend) è una buona soluzione perché mantieni la conversione int:

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

Vedrai 55 come int.


4
Oppure "0$id" => $value. Anche in preparazione con i 0lavori.
nawfal

Quindi stai dicendo che non è possibile utilizzare una stringa numerica come "123" come chiave in un array PHP, senza che venga convertita in un numero intero?
Flimm

5

Puoi digitare la chiave in una stringa, ma alla fine verrà convertita in un numero intero a causa della digitazione libera di PHP. Guarda tu stesso:

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

Dal manuale PHP:

Una chiave può essere un numero intero o una stringa. Se una chiave è la rappresentazione standard di un numero intero, verrà interpretata come tale (cioè "8" sarà interpretato come 8, mentre "08" sarà interpretato come "08"). I float nella chiave vengono troncati a intero. I tipi di array indicizzati e associativi sono dello stesso tipo in PHP, che possono contenere sia indici interi che stringhe.


1
La conversione non è dovuta a errori di battitura; php determina se la stringa sembra numerica e quindi la converte.
Ja͢ck

1
Quindi stai dicendo che non è possibile? Questa risposta mostra che esiste un modo per utilizzare una stringa che assomiglia a un numero intero come chiave in un array.
Flimm

IMHO il problema è l'interprete PHP. Non è nemmeno possibile immaginare di avere un linguaggio che mescoli stringhe e numeri interi come chiavi di array. La migliore soluzione? Come proposto dalla Undolog stackoverflow.com/a/15413637/1977778 la soluzione migliore è quella di utilizzare uno spazio finale ... Purtroppo.
sentenza

@sentenza: Si è possibile immaginare, soprattutto perché PHP permette una miscela di stringhe e numeri interi, come le chiavi di un array:[42 => 'answer', 'snafu' => 'fubar']
LS

@LS yep. So che PHP ti consente di farlo, ma se consideri le chiavi all'interno di un ipotetico sistema di tipi generico non corrisponderà a nessun tipo misto che abbraccia stringhe e numeri allo stesso tempo. La digitazione libera applicata alle chiavi di un array associativo è semplicemente soggetta a errori.
sentenza

1

Ho avuto questo problema cercando di unire array che avevano chiavi sia stringa che intere. Era importante che anche gli interi venissero gestiti come stringhe poiché si trattava di nomi per i campi di input (come nelle misure delle scarpe, ecc.)

Quando ho usato $data = array_merge($data, $extra);PHP avrei "riordinato" le chiavi. Nel tentativo di eseguire l'ordinamento, le chiavi intere (ho provato con 6- '6'- "6"anche (string)"6"come chiavi) sono state rinominate da 0 a n... Se ci pensi, nella maggior parte dei casi questo sarebbe il comportamento desiderato.

Puoi aggirare questo problema usando $data = $data + $extra;invece. Abbastanza semplice, ma all'inizio non ci ho pensato ^^.


Lo stesso identico problema mi ha portato a questa pagina, ma devo dire che questa non è la risposta alla domanda di OP.
Flimm

@Flimm True. Ma la ricerca di una risposta mi ha portato a questa pagina. Ho pensato che la mia soluzione potesse essere un aiuto per altri googler :)
Brainfeeder

1

Le stringhe contenenti numeri interi validi verranno convertiti nel tipo intero. Ad esempio, la chiave "8" verrà effettivamente memorizzata sotto 8. D'altra parte "08" non verrà lanciato, poiché non è un numero intero decimale valido.

SBAGLIATO

Ho una funzione di casting che gestisce il casting da array sequenziale a associativo,

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

1

Come soluzione alternativa, puoi codificare l'array PHP in un oggetto json, con l'opzione JSON_FORCE_OBJECT.

cioè, questo esempio:

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

si tradurrà in:

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

0

Mi sono imbattuto in questo problema su un array con entrambi '0' e '' come chiavi. Significava che non potevo controllare le mie chiavi array 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 soluzione alternativa consiste nel eseguire il cast delle chiavi dell'array sulle stringhe prima dell'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
Questa non è davvero una risposta alla domanda.
Flimm

0

Per quanto riguarda la soluzione @david, si noti che quando si tenta di accedere ai valori di stringa nell'array associativo, i numeri non funzioneranno. La mia ipotesi è che vengano trasmessi a numeri interi dietro le quinte (quando si accede all'array) e non viene trovato alcun valore. Anche l'accesso ai valori come numeri interi non funzionerà. Ma puoi usare array_shift () per ottenere i valori o iterare l'array.

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

Quale versione di php? Ho provato esattamente il tuo esempio e la chiave "0"diventa 0con php 7.2.10.
J.BizMai

-1

Ho avuto questo problema durante il tentativo di ordinare un array in cui avevo bisogno che la chiave di ordinamento fosse un hex sha1. Quando un valore sha1 risultante non ha lettere, PHP trasforma la chiave in un numero intero. Ma avevo bisogno di ordinare l'array sull'ordine relativo delle stringhe. Quindi dovevo trovare un modo per forzare la chiave in modo che fosse una stringa senza modificare l'ordine di ordinamento.

Guardando il grafico ASCII ( https://en.wikipedia.org/wiki/ASCII ) il punto esclamativo si ordina quasi come lo spazio e sicuramente inferiore a tutti i numeri e le lettere.

Quindi ho aggiunto un punto esclamativo alla fine della stringa chiave.

for(...) {

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

ksort($database);
$row = reset($database);
$topsha = $row[0];

Quindi stai dicendo che non è possibile utilizzare una stringa numerica come "123" come chiave in un array PHP, senza che venga convertita in un numero intero?
Flimm

No - tratta solo la chiave composta da tutti i numeri come un numero intero quando si ordina l'array usando ksort () - non viene mai convertito in un numero intero - solo confrontato come uno durante l'ordinamento.
drchuck
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.