PHP verhält sich wie folgt, wenn man den jeweiligen Datentyp als Array-Schlüssel verwendet:
- Integer: Darf uneingeschränkt verwendet werden und wird auch vermutlich am häufigsten verwendet.
- Float: Wird in Integer umgewandelt indem die Nachkommastellen abgeschnitten werden (wie $int = (int)$float).
- String: Darf uneingeschränkt verwendet werden. Es gibt keine Einschränkung der erlaubten Zeichen. Auch leere Strings sind erlaubt.
- NULL: Wird in einen leeren String umgewandelt.
- Array: Ist nicht erlaubt. Bei Verwendung als Schlüssel wird kein Element hinzugefügt und eine Warnung erzeugt.
- Objekt: Ist nicht erlaubt. Bei Verwendung als Schlüssel wird kein Element hinzugefügt und eine Warnung erzeugt.
1. Einleitung
Dieser Artikel analysiert, welche Datentypen als Schlüssel von Arrays in PHP benutzt werden dürfen und was passiert, wenn ein nicht erlaubter Datentyp verwendet wird. Die Betrachtung umfasst Integer, Float, String, NULL und Array, sowie Objekte.
2. Integer
Im nächsten Beispiel wird die Verwendung von Integern als Array-Schlüssel getestet. Es werden die Zahlen -1, 0, 1, sowie die obere Schranke für Integer überprüft (PHP_INT_MAX). Anschließend wird das Array ausgegeben. Statt var_dump() wird dafür eine eigene kleine Schleife implementiert, da var_dump() standardmäßig nicht explizit die Datentypen der Array-Schlüssel anzeigt. Die Schleife macht nichts anderes, als über alle Elemente zu iterieren und zu jedem dieser Elemente jeweils den Datentyp des Schlüssels, den Schlüssel als String und den Wert auszugeben.
<?php $arr[-1] = 'test von -1'; $arr[0] = 'test von 0'; $arr[1] = 'test von 1'; // Hinweis: bei PHP_INT_MAX + 1 verwendet PHP den Minimalwert // für Integer (PHP_INT_MAX * (-1)) $arr[PHP_INT_MAX] = 'test von max'; foreach ($arr as $key=>$val) { echo("(".gettype($key).")".(string)$key.": $val\n"); } ?>
(integer)-1: test von -1 (integer)0: test von 0 (integer)1: test von 1 (integer)2147483647: test von max
Wie dem Beispiel zu entnehmen ist, können Integer-Werte ohne Einschränkungen als Array-Schlüssel benutzt werden. Tatsächlich werden sie vermutlich auch am häufigsten verwendet, denn immer wenn kein Schlüssel explizit angegeben wird, weist PHP automatisch einen Integer zu. Als Wert für diesen Integer wählt PHP immer den bisher größten Integer-Schlüssel plus eins.
<?php $arr = array( 'I', // 0 => "I" 'a' => 'II', 'III', // 1 => "III" 100 => 'IV', 'V', // 101 => "V" 70 => 'VI', 'VII', // 102 => "VII" 150 => 'VIII', 110 => 'IX', 'X' // 151 => "X" ); foreach ($arr as $key=>$val) { echo("(".gettype($key).")".(string)$key.": $val\n"); } ?>
(integer)0: I (string)a: II (integer)1: III (integer)100: IV (integer)101: V (integer)70: VI (integer)102: VII (integer)150: VIII (integer)110: IX (integer)151: X
3. Float
Floats können nicht als Array-Schlüssel verwendet werden. Statt einer Warnung oder einem Notice (oder gar einem echten Fehler) wandelt PHP diese klammheimlich in Integer um. Die Kovertierung findet statt, indem alle Nachkommastellen abgeschnitten werden, was der Anwendung von $schluessel = (int)$float entspricht. (Das ist nicht identisch mit floor($float), da floor() etwa -1.7 zu -2.0 abrundet — nur bei positiven Zahlen sind floor($float) und (int)$float identisch.)
Das nächste Beispiel demonstriert die Verwendung von Floats als Array-Schlüssel. Wie im Abschnitt zu Integern wird versucht, ein Array mit mehreren Floats als Schlüssel anzulegen. Diese werden am Ende wieder über eine kleine Schleife ausgegeben, welche im Gegensatz zu var_dump() auch die Datentypen der Schlüssel explizit anzeigt. In dem Beispiel ist gut zu erkennen, dass Floats überschrieben werden können, wenn diese nach Anwendung von (int)$float identisch sind, da letztlich dem selben Integer-Schlüssel zwei mal ein Wert zugewiesen wird.
<?php $arr[-1.5] = 'test von -1.5'; $arr[0.0] = 'test von 0.0'; $arr[1.5] = 'test von 1.5'; $arr[1/3] = 'test von 1/3'; $arr[2/3] = 'test von 2/3'; foreach ($arr as $key=>$val) { echo("(".gettype($key).")".(string)$key.": $val\n"); } ?>
(integer)-1: test von -1.5 (integer)0: test von 2/3 (integer)1: test von 1.5
Hinweis: Aufgrund der Ungenauigkeit von Floats wäre ihre Anwendung als Schlüssel ohnehin problematisch, selbst wenn PHP dies erlauben würde.
4. String
Strings können ohne Einschränkungen als Schlüssel für Arrays verwendet werden. Auch Sonderzeichen und leere Strings sind erlaubt. Das nächste Beispiel demonstriert die Anwendung, der Aufbau entspricht den vorherigen Beispielen.
<?php $arr['bla'] = 'test von "bla"'; $arr[''] = 'test von "" (leerer String)'; $arr['~'] = 'test von "~"'; $arr["\n"] = 'test von "\n" (Zeilenumbruch)'; foreach ($arr as $key=>$val) { echo("(".gettype($key).")".(string)$key.": $val\n"); } ?>
(string)bla: test von "bla" (string): test von "" (leerer String) (string)~: test von "~" (string) : test von "\n" (Zeilenumbruch)
Einzig problematisch bei der Verwendung von String-Schlüsseln sind solche, die nur Ziffern (0-9) enthalten (optional mit negativem Vorzeichen). Diese werden von PHP automatisch in Integer umgewandelt, vorausgesetzt sie beginnen nicht mit einer 0 und liegen innerhalb des gültigen Integerbereichs. In Ausnahmefällen kann dies zu unerwartetem Verhalten führen, daher sollte man für Integer-Schlüssel auch tatsächlich Integer verwenden und diese nicht in Strings einbetten.
<?php // --- // Diese String-Schlüssel werden in Integer umgewandelt // --- // Integer-ähnliche Strings $arr['-1'] = 'test von "-1"'; // Schlüssel wird zu (integer)-1 $arr['0'] = 'test von "0"'; // (integer)0 $arr['1'] = 'test von "1"'; // (integer)1 $arr['2147483647'] = 'test von PHP_INT_MAX auf Testsystem'; // (integer)2147483647 // --- // Die nachfolgenden String-Schlüssel werden nicht in Integer umgewandelt // --- // Integer-ähnliche Strings $arr['01'] = 'test von "01"'; // (string)"01" ! $arr['+0'] = 'test von "+0"'; // (string)"+0" ! $arr['2147483648'] = 'test von PHP_INT_MAX + 1 auf Testsystem'; // (string)"2147483648" // Float-ähnliche Strings $arr['1.1'] = 'test von "1.1"'; // (string)"1.1" // Nicht nur Ziffern $arr['1a'] = 'test von "1a"'; // (string)"1a" $arr['a1'] = 'test von "a1"'; // (string)"a1" // Mit Leerzeichen $arr['1 '] = 'test von "1 "'; // (string)"1 " $arr[' 1'] = 'test von " 1"'; // (string)" 1" $arr[' 1 '] = 'test von " 1 "'; // (string)" 1 " // Hex-String $arr['0xFF'] = 'test von "0xFF"'; // (string)"0xFF" foreach ($arr as $key=>$val) { echo("(".gettype($key).")".(string)$key.": $val\n"); } ?>
(integer)-1: test von "-1" (integer)0: test von "0" (integer)1: test von "1" (integer)2147483647: test von PHP_INT_MAX auf Testsystem (string)01: test von "01" (string)+0: test von "+0" (string)2147483648: test von PHP_INT_MAX + 1 auf Testsystem (string)1.1: test von "1.1" (string)1a: test von "1a" (string)a1: test von "a1" (string)1 : test von "1 " (string) 1: test von " 1" (string) 1 : test von " 1 " (string)0xFF: test von "0xFF"
5. Boolean
Boolean-Werte können nicht als Array-Schlüssel verwendet werden. Sie werden von PHP kommentarlos in Integer umgewandelt. (false wird zu 0, true zu 1.)
<?php $arr[false] = 'test von false'; $arr[true] = 'test von true'; foreach ($arr as $key=>$val) { echo("(".gettype($key).")".(string)$key.": $val\n"); } ?>
(integer)0: test von false (integer)1: test von true
6. NULL
NULL kann nicht als Array-Schlüssel verwendet werden, sondern wird von PHP automatisch in einen leeren String umgewandelt.
<?php $arr[null] = 'test von null'; foreach ($arr as $key=>$val) { echo("(".gettype($key).")".(string)$key.": $val\n"); } ?>
(string): test von null
7. Array
Arrays sind keine gültigen Array-Schlüssel. Im Gegensatz zu den anderen nicht erlaubten Datentypen (Float, Boolean, NULL) führt ihre Anwendung zu einer „Illegal offset type”-Warnung. Das restliche Skript wird weiter ausgeführt, da es sich „nur” um eine Warnung handelt. Das Array bleibt bei Zuweisungen mit Arrays als Schlüssel leer.
<?php $arr[array()] = 'test von array()'; $arr[array(1, 2, 3)] = 'test von array(1, 2, 3)'; $arr[array('foo'=>'bar')] = 'test von array(foo => bar)'; foreach ($arr as $key=>$val) { echo("(".gettype($key).")".(string)$key.": $val\n"); } var_dump(count($arr)); // erzeugt 0 ?>
<br /> <b>Warning</b>: Illegal offset type in <b>...\test.php</b> on line <b>2</b><br /> <br /> <b>Warning</b>: Illegal offset type in <b>...\test.php</b> on line <b>3</b><br /> <br /> <b>Warning</b>: Illegal offset type in <b>...\test.php</b> on line <b>4</b><br /> int(0)
8. Objekt
Genau wie Arrays sind auch Objekte nicht als Array-Schlüssel erlaubt. Wieder verursacht ihre Benutzung „Illegal offset type”-Warnungen. Dabei spielt es keine Rolle, ob das Objekt eine toString-Methode implementiert oder nicht.
<?php class MyObject { } class MyObjectToString { public function __toString() { return 'test'; } } $arr[new MyObject()] = 'test von MyObject'; $arr[new MyObjectToString()] = 'test von MyObjectToString'; foreach ($arr as $key=>$val) { echo("(".gettype($key).")".(string)$key.": $val\n"); } var_dump(count($arr)); // erzeugt 0 ?>
<br /> <b>Warning</b>: Illegal offset type in <b>...\test.php</b> on line <b>9</b><br /> <br /> <b>Warning</b>: Illegal offset type in <b>...\test.php</b> on line <b>10</b><br /> array(0) { }