Eine numerische Zeichenfolge als Array-Schlüssel in PHP

104

Ist es möglich, eine numerische Zeichenfolge wie "123"einen Schlüssel in einem PHP-Array zu verwenden, ohne sie in eine Ganzzahl umzuwandeln?

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

druckt

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

Ich will

array(1) {
  ["123"]=>
  int(1)
}
Dogbert
quelle
7
Da PHP lose typisiert ist, "123"== 123für fast jeden Zweck. Was ist der Grund, warum Sie es speziell als String wollen (und ein Int zu haben ist schlecht)?
Ircmaxell
17
Der Grund, der mir in den Sinn kommt, bezieht sich auf Array-Funktionen wie array_merge "Wenn die Eingabearrays dieselben Zeichenfolgenschlüssel haben, überschreibt der spätere Wert für diesen Schlüssel den vorherigen. Wenn die Arrays jedoch numerische Schlüssel enthalten , wird der spätere Wert dies nicht tun." überschreibt den ursprünglichen Wert, wird aber angehängt. "
Ficuscr
8
Ein weiteres Beispiel, bei dem numerische Zeichenfolgen als Array-Schlüssel problematisch sind:asort
Swenedo
4
Ein weiterer Anwendungsfall: Unit-Test des JSON-Datenübergangs. Wenn Sie ein solches Array in JSON und zurück konvertieren, können Sie nicht behaupten, dass sowohl das Original als auch das Ergebnis genau gleich sind.
David

Antworten:

90

Nein; Nein, ist es nicht:

Aus dem Handbuch :

Ein Schlüssel kann entweder eine Ganzzahl oder eine Zeichenfolge sein. Wenn ein Schlüssel die Standarddarstellung einer Ganzzahl ist, wird er als solcher interpretiert (dh "8" wird als 8 interpretiert, während "08" als "08" interpretiert wird).

Nachtrag

Aufgrund der folgenden Kommentare dachte ich, es würde Spaß machen, darauf hinzuweisen, dass das Verhalten ähnlich, aber nicht identisch mit JavaScript-Objektschlüsseln ist.

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

foo['10']; // "bar"
foo[10]; // "bar"
foo[012]; // "bar"
foo['012']; // undefined!
Hamish
quelle
106
PHP, der serverseitige IE.
Marek Maurizio
5
Es sieht so aus, als gäbe es tatsächlich einen Weg! Stimmen Sie dieser Antwort nicht zu? stackoverflow.com/a/35180513/247696
Flimm
1
Wie ?! .. foo "bar" zurückgeben
Himanshu
1
@Himanshu: weil PHP Zahlen, die mit 0 beginnen, als Oktal interpretiert. 012 ist also Oktal 10.
Yeasir Arafat Majumder
48

Ja, es ist durch Array-Casting eines stdClassObjekts möglich:

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

Das gibt Ihnen (bis PHP Version 7.1):

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

(Update: Meine ursprüngliche Antwort zeigte einen komplizierteren Weg mit json_decode()und json_encode()der nicht notwendig ist.)

Beachten Sie den Kommentar : Es ist leider nicht möglich, den Wert direkt zu referenzieren: $data['12']Dies führt zu einem Hinweis.

Update :
Ab PHP 7.2 auf es ist auch möglich , eine numerische Zeichenfolge als Schlüssel zu verwenden , um den Wert zu verweisen:

var_dump( $data['12'] ); // int 32
David
quelle
2
Der direkte Zugriff auf den Wert mit einem Zeichenfolgenschlüssel funktioniert jedoch nicht. Fügen Sie diese Zeile Ihrem Beispiel hinzu : echo $data['12'];. Es wird der Fehler "Hinweis: Undefinierter Versatz: 12 Zoll in Zeile 5" angezeigt.
LS
1
Wenn Sie laravel dd ($ data) verwenden, stürzt es ab: P
Kamil Kiełczewski
2
In PHP 7.2.0RC2 ist das Verhalten das gleiche wie zuvor.
dev0
1
Anscheinend array_key_existswird es auch in den älteren Versionen nicht gefunden.
Keine Panik
1
funktioniert nicht in PHP 7.4
Jasmin
12

Wenn Sie einen numerischen Schlüssel in einer PHP-Datenstruktur verwenden müssen, funktioniert ein Objekt. Und Objekte behalten die Ordnung bei, sodass Sie iterieren können.

$obj = new stdClass();
$key = '3';
$obj->$key = 'abc';
dampfbetrieben
quelle
Dies ist ein sehr guter Vorschlag. Ich schreibe Framework-Code und bin mit jemandem konfrontiert, der ein Array übergibt, das entweder eine "versehentliche" Indizierung haben könnte: Array ('this', 'that') oder eine "assoziative" Indizierung: array (123 => array ('this', 'that) ')). Jetzt, dank dir, kann ich nur tippen;) +1
Just Plain High
Aber ist es möglich, eine numerische Zeichenfolge wie "123" als Schlüssel in einem PHP-Array zu verwenden, ohne dass sie in eine Ganzzahl konvertiert wird?
Flimm
@Flimm nein das ist nicht möglich, deshalb biete ich meine lösung an.
Steampowered
@Flimm diese Antwort scheint dem PHP-Handbuch zu widersprechen : Strings, die gültige Ganzzahlen enthalten, werden in den Ganzzahltyp umgewandelt. ZB wird der Schlüssel "8" tatsächlich unter 8 gespeichert. Andererseits wird "08" nicht umgewandelt, da es sich nicht um eine gültige Dezimalzahl handelt. , obwohl ich seine Antwort nicht getestet habe.
Steampowered
Dieser Satz befindet sich unter dem Abschnitt "Angeben mit array(), daher gehe ich davon aus, dass in diesem Kontext Zeichenfolgen, die gültige Ganzzahlen angeben , in den Ganzzahltyp umgewandelt werden. Es stellt sich jedoch heraus, dass es andere Möglichkeiten gibt, Arrays zu erstellen, bei denen dies nicht der Fall ist. wie in Davids Antwort, die ich getestet habe.
Flimm
10

Meine Problemumgehung ist:

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

Das Leerzeichen char (prepend) ist eine gute Lösung, da die int-Konvertierung beibehalten wird:

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

Sie sehen 55 als int.

Undolog
quelle
4
Oder "0$id" => $value. Vorarbeiten mit 0Arbeiten auch.
Nawfal
@nawfal danke Mann, ich hatte nicht erwartet, die Antwort hier unten zu finden
Va1iant
Sie sagen also, dass es nicht möglich ist, eine numerische Zeichenfolge wie "123" als Schlüssel in einem PHP-Array zu verwenden, ohne dass sie in eine Ganzzahl konvertiert wird?
Flimm
5

Sie können den Schlüssel in eine Zeichenfolge eingeben, er wird jedoch aufgrund der losen Eingabe von PHP möglicherweise in eine Ganzzahl konvertiert. Überzeugen Sie sich selbst:

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

Aus dem PHP-Handbuch:

Ein Schlüssel kann entweder eine Ganzzahl oder eine Zeichenfolge sein. Wenn ein Schlüssel die Standarddarstellung einer Ganzzahl ist, wird er als solcher interpretiert (dh "8" wird als 8 interpretiert, während "08" als "08" interpretiert wird). Gleitkommazahlen werden auf Ganzzahl gekürzt. Der indizierte und der assoziative Array-Typ sind in PHP vom selben Typ, der sowohl Ganzzahl- als auch Zeichenfolgenindizes enthalten kann.

bcosca
quelle
1
Die Konvertierung ist nicht auf lose Eingabe zurückzuführen. PHP bestimmt, ob die Zeichenfolge numerisch aussieht, und konvertiert sie dann.
Ja͢ck
Wollen Sie damit sagen, dass es nicht möglich ist? Diese Antwort zeigt, dass es eine Möglichkeit gibt, eine Zeichenfolge zu verwenden, die wie eine Ganzzahl als Schlüssel in einem Array aussieht.
Flimm
IMHO ist das Problem der PHP-Interpreter. Es ist nicht einmal vorstellbar, eine Sprache zu haben, die Zeichenfolgen und Ganzzahlen als Array-Schlüssel mischt. Die beste Lösung? Wie von Undolog stackoverflow.com/a/15413637/1977778 vorgeschlagen, besteht die beste Lösung darin, ein nachfolgendes Leerzeichen zu verwenden ... Leider.
Sentenza
@sentenza: Es ist vorstellbar, zumal PHP eine Mischung aus Strings und Integer als Schlüssel eines Arrays zulässt:[42 => 'answer', 'snafu' => 'fubar']
LS
@ LS yep. Ich weiß, dass PHP dies ermöglicht, aber wenn Sie die Schlüssel in einem hypothetischen generischen Typsystem berücksichtigen, stimmt es nicht mit einem gemischten Typ überein , der gleichzeitig Zeichenfolgen und Zahlen umfasst. Die lose Eingabe, die auf die Schlüssel eines assoziativen Arrays angewendet wird, ist einfach fehleranfällig.
Sentenza
1

Ich hatte dieses Problem beim Versuch, Arrays zusammenzuführen, die sowohl Zeichenfolgen- als auch Ganzzahlschlüssel hatten. Es war wichtig, dass die Ganzzahlen auch als Zeichenfolge behandelt werden, da dies Namen für Eingabefelder waren (wie bei Schuhgrößen usw.).

Wenn ich $data = array_merge($data, $extra);PHP benutzte, ordnete ich die Schlüssel neu. Bei einem Bestellversuch wurden die Ganzzahlschlüssel (ich habe es mit 6- '6'- "6"auch (string)"6"als Schlüssel versucht ) von 0 in n... umbenannt. Wenn Sie darüber nachdenken, wäre dies in den meisten Fällen das gewünschte Verhalten.

Sie können dies umgehen, indem Sie $data = $data + $extra;stattdessen verwenden. Ziemlich einfach, aber ich habe zuerst nicht daran gedacht ^^.

Brainfeeder
quelle
Das exakt gleiche Problem hat mich zu dieser Seite geführt, aber ich muss sagen, dass dies keine Antwort auf die Frage von OP ist.
Flimm
@ Flimm True. Aber die Suche nach einer Antwort führte mich zu dieser Seite. Ich dachte, meine Lösung könnte eine Hilfe für andere Googler sein :)
Brainfeeder
1

Zeichenfolgen, die gültige Ganzzahlen enthalten, werden in den Ganzzahltyp umgewandelt. ZB wird der Schlüssel "8" tatsächlich unter 8 gespeichert. Andererseits wird "08" nicht umgewandelt, da es sich nicht um eine gültige Dezimalzahl handelt.

FALSCH

Ich habe eine Casting-Funktion, die sequentielles bis assoziatives Array-Casting handhabt.

$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
quelle
funktioniert nicht in PHP 7.4
Jasmin
1

Um dieses Problem zu umgehen, können Sie das PHP-Array mit der Option JSON_FORCE_OBJECT in ein JSON-Objekt codieren.

dh dieses Beispiel:

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

wird darin enden, dass:

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

Ich bin auf ein Array mit '0' und '' als Schlüssel gestoßen. Dies bedeutete, dass ich meine Array-Schlüssel weder mit == noch mit === überprüfen konnte.

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

Die Problemumgehung besteht darin, die Array-Schlüssel vor der Verwendung wieder in Zeichenfolgen umzuwandeln.

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
quelle
1
Dies ist keine wirkliche Antwort auf die Frage.
Flimm
0

Beachten Sie in Bezug auf die @ David-Lösung, dass die Zahlen nicht funktionieren, wenn Sie versuchen, auf die Zeichenfolgenwerte im assoziativen Array zuzugreifen. Ich vermute, dass sie hinter den Kulissen (beim Zugriff auf das Array) in ganze Zahlen umgewandelt werden und kein Wert gefunden wird. Der Zugriff auf die Werte als Ganzzahlen funktioniert ebenfalls nicht. Sie können jedoch array_shift () verwenden, um die Werte abzurufen oder das Array zu iterieren.

$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
quelle
Welche PHP-Version? Ich habe genau dein Beispiel ausprobiert und der Schlüssel "0"wird 0mit PHP 7.2.10.
J.BizMai
-1

Ich hatte dieses Problem beim Versuch, ein Array zu sortieren, bei dem der Sortierschlüssel ein Hex sha1 sein musste. Wenn ein resultierender sha1-Wert keine Buchstaben enthält, wandelt PHP den Schlüssel in eine Ganzzahl um. Aber ich musste das Array nach der relativen Reihenfolge der Zeichenfolgen sortieren. Also musste ich einen Weg finden, den Schlüssel als String zu erzwingen, ohne die Sortierreihenfolge zu ändern.

In der ASCII-Tabelle ( https://en.wikipedia.org/wiki/ASCII ) ist das Ausrufezeichen ungefähr gleich groß wie das Leerzeichen und sicherlich niedriger als alle Zahlen und Buchstaben.

Also habe ich ein Ausrufezeichen am Ende der Schlüsselzeichenfolge angehängt.

for(...) {

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

ksort($database);
$row = reset($database);
$topsha = $row[0];
drchuck
quelle
Wollen Sie damit sagen, dass es nicht möglich ist, eine numerische Zeichenfolge wie "123" als Schlüssel in einem PHP-Array zu verwenden, ohne dass sie in eine Ganzzahl konvertiert wird?
Flimm
Nein - beim Sortieren des Arrays mit ksort () wird nur der Schlüssel, bei dem es sich um alle Zahlen handelt, als Ganzzahl behandelt. Er wird niemals in eine Ganzzahl konvertiert. Er wird beim Sortieren nur als einer verglichen.
Drchuck