PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


PHP und die lose Typisierung

with 6 comments

Heute mal eine sehr praktische Erfahrung:

Der Kollege nebenan fragte, ob ich mal kurz rübergucken kann, er verstehe die Ausgabe einer Funktion nicht. Vereinfacht sah der Code so aus (über Sinn und Unsinn soll hier nicht diskutiert werden, es ist nur vereinfacht dargestellt):

function show(array $headerArray) {
	foreach ($headerArray as $headerKey => $headerValue) {
		$outputString = $headerKey . ':';
		foreach ($headerValue as $valueKey => $value) {
			if ($valueKey != 'append') {
				$outputString .= $value;
			}
		}
		return $outputString;
	}
}

Die Funktion erwartet ein Array mit Header-Informationen. Diese sollen durchlaufen werden, und die Inhalte sollen als Wertepaare-String zurückgegeben werden, wenn der innere Key nicht „append“ ist.

Soweit ist der Code OK. Jetzt kommt der Aufruf:

$headerArray = array("From" => array(
						0 		=> 'john.doe@some.city',
						'append'=> true			));

echo show($headerArray);

Wie lautet die Ausgabe? Korrekt, nämlich so:

From:

Wenn ich den Aufruf leicht ändere:

$headerArray = array("From" => array(
						'0' 		=> 'john.doe@some.city',
						'append'=> true			));

echo show($headerArray);

Wir nutzen also als Key nun den String ‚0‘. Jetzt sollte das richtige rauskommen. Aber man liegt immernoch falsch:

From:

Da wurde ich stutzig. Man sollte denken, jetzt wird der String ‚0‘ mit dem String ‚append‘ verglichen. Da es ungleich ist, sollte die Email-Adresse ausgegeben werden. Falsch gedacht.

PHP scheint den Key eines Arrays als Integer zu casten wenn möglich. Egal ob wir 0 oder ‚0‘ als Key verwenden, beim Auslesen des Arrays erhalten wir immer einen Integerwert. Das sollte man sich auf der Zunge zergehen lassen.
Als Folge vergleicht er also immer den Integer 0 mit dem String ‚append‘. Damit ein Vergleich möglich ist, castet PHP den String korrekterweise als Integer, und das ergibt ja bekannterweise 0.

Das ursprüngliche Problem lag natürlich beim != . Man hätte das ganze vermeiden können, indem man !== verwendet, dann wäre das Problem nicht aufgetreten, und ich hätte einen Artikel weniger.

Written by Michael Kliewe

Oktober 12th, 2009 at 12:02 pm

Posted in PHP

Tagged with , ,

6 Responses to 'PHP und die lose Typisierung'

Subscribe to comments with RSS or TrackBack to 'PHP und die lose Typisierung'.

  1. Oh ja, die Erfahrung durfte ich auch schon häufiger machen. Ich hatte aber auch schon das Gegenteil. Immer fein mit === / !== Felder überprüft und dann kamen die Daten mal „falsch“ an und ich hab ewig den Fehler gesucht.

    Die Erfahrung daraus war für mich, dass ich keine Überprüfungen mit === mehr mache, wenn ich nicht vorher den Variablentyp gesetzt oder überprüft habe.

    Bastian

    12 Okt 09 at 14:01

  2. PHP wandelt sämtliche Array-Keys, die Zahlendarstellung sind, in Integer. Man kann also keinen String „0“ als Key haben, das wird immer Integer 0 werden (entsprechendes gilt für alle anderen Zahlen).

    Deshalb wird in dem Vergleich immer der Fall eintreten, dass Integer mit String verglichen wird, war bei dem losen Vergleich mit == dazu führt, dass der String in eine Zahl gewandelt wird.

    Doku-Links:
    http://de3.php.net/manual/en/language.types.array.php
    ‚If a key is the standard representation of an integer, it will be interpreted as such (i.e. „8“ will be interpreted as 8, while „08“ will be interpreted as „08“). Floats in key are truncated to integer.‘

    http://de3.php.net/manual/en/language.operators.comparison.php
    ‚If you compare an integer with a string, the string is converted to a number.‘

    http://de3.php.net/manual/en/types.comparisons.php

    Sven Rautenberg

    14 Okt 09 at 09:22

  3. Genau das ist es, was wir herausgefunden haben 😉 Intuitiv ist die Umwandlung der Keys in einen Integer aber nicht, denn Strings sind ja auch möglich. Warum wandelt PHP da also automatisch etwas um?

    Michael Kliewe

    14 Okt 09 at 10:04

  4. Das „Warum“ beantwortet die Doku natürlich nicht.

    Aber mal spekulieren: Arrays und somit auch die Behandlung der Keys ist uraltes PHP-Interieur, also werden da Dinge gemacht, die auf dem gleichen Level liegen wie „magic_quotes“ und „register_globals“, sprich: DAU-Error-Verhinderungsmaßnahmen und ähnliches. Oder ganz schlicht Maßnahmen, die in einer lose typisierten Sprache notwendig sind.

    Was ist denn typisches Anwendungsszenario für PHP: a) Verarbeitung von POST- und GET-Daten (alles Strings) und b) Verarbeitung von DB-Daten (Typ abhängig von der Spalte).

    Wenn jetzt das Webfrontend als Datensatz-Schlüssel (string)“123″ liefert, die Datenbank aber (int)123, und man versucht, beide Informationen über den jeweiligen Key in einem Array zu finden, würde das Vorhaben mutmaßlich scheitern, wenn sich die Hashwerte unterscheiden.

    Oder mindestens doppelt so viel Zeit kosten und zu unschönen Doppelproblemen führen, weil beide Möglichkeiten (Key „123“ !== Key 123) geprüft werden müssten. Was ist, wenn beide Keys existieren? Keine gute Idee!

    Vielleicht hat sich auch einfach irgendwann als schlau herausgestellt, dass für numerische Keys die Wandlung in einen Integer die schlauste Methode ist.

    Sven Rautenberg

    14 Okt 09 at 10:43

  5. Es mag in vielen Fällen sinnvoll sein, in diesem Fall standen wir mit offenem Mund vor dem Code. Bisher hat auch keiner, den wir danach gefragt haben, dieses Verhalten so erwartet.

    Man könnte es auch positiv ausdrücken: Mit PHP lernt man jeden Tag etwas Neues!

    Michael Kliewe

    14 Okt 09 at 10:55

  6. Ich hab das auch grad mal getestet und bin sicher genauso erstaunt gewesen, wie jeder andere auch. Das scheint aber in irgendeiner Form auch nen Bug zu sein, weil 0!=’append‘ sollte in jedem Fall true zurückgeben ob nun string oder int… Oder sehe ich das falsch?

    Stefan Riedels Blog

    27 Okt 09 at 13:54

Leave a Reply

You can add images to your comment by clicking here.