PHP: array_merge

with tags Softwareschrott Technik -

Kommen wir mal wieder zu den wirklich ekligen Sachen im täglichen Berufsleben: z.B. die diversen Eigenarten von PHP. Jeder der sich schonmal mehr als 3-4 Sprachen angesehen hat wird wohl bemerken was für eine Qual die Arbeit mit dynamischer Typisierung manchmal wird.

Wirklich schlimm wird das aber erst, wenn man an eine Stelle kommt, da man keinen direkten Einfluss auf die interpretierten Datentypen hat, sprich: wenn ich eine bereits vorliegende Funktion verwende und mit ihrer Funktionsweise leben muss. Ein typischer Fall für dies, der mich jedes Mal aufs neue nervt ist die Art wie die PHP-internen Array-Funktionen definiert sind. Erstmal grundsätzlich finde ich es ja nicht schlimm dass die Autoren von PHP sich offensichtlich nicht entscheiden konnten ob sie nun Arrays oder Dictioneries implementieren wollten. Natürlich kann man beide Konzepte für einfache Operationen gleich verwenden, wenn es jedoch an komplexere Sachen geht sollte man sich verdammt nochmal an ein Konzept halten!

Jedenfalls hat PHP nun seine Dictionaries die als Arrays bezeichnet werden und Funktionen die sich nicht entscheiden können womit sie arbeiten wollen. Dies kombiniert mit der Schwäche nicht entscheiden zu können ob es sich bei dem String den ein Nutzer gerade eingegeben hat um einen Integer oder einen String handelt, sorgt für Aktionen bei denen einem die Haare zu berge stehen.

Wenn ich z.B. zwei assoziative Arrays mit array_merge zu einem Zusammenschieben will, so reagiert PHP komplett unterschiedlich, je nachdem welche Keys vergeben werden.
Werden reine Integer-Werte verwendet, so kann PHP nicht erkennen dass ess sich um manuell festgelegte Schlüssel handelt, es sieht nach einem normalen Array aus in dem den Values keine bewusst gewählten Keys zugewiesen wurden. In diesem Fall macht also array_merge nicht viel mehr als die beiden Arrays hintereinander zu hängen.

Wenn jedoch ganz eindeutige Strings als Keys vergeben werden, so reagiert die Funktion anders. Hier ist ja eindeutig sichtbar dass jemand einen Wert an einer ganz bestimmten Stelle speichern wollte, also werden die Werte überschrieben.

In der Praxis bedeutet das also, dass wenn ich folgende Arrays jeweils mit sich selbst merge, ich komplett unterschiedliche Ergebnisse erhalte

array(1=>1, 2=>2)ergibt mit sich selbst gemergt ein 4-Stelliges Array: array(1,2,1,2)
array('a'=>'a', 'b'=>'b') ergibt jedoch dank überschreibung nur sich selbst, wenn man es mit sich selbst merged

Das mag jetzt für sich genommen nervig sein und imho gibt es auch keinen Grund warum man eine Funktion braucht die auf Integer-Keys angewendet exakt das Selbe tut wie wenn ich einfach die Arrays mit + zusammenhänge.
Wenn ich jetzt jedoch noch mit in Betracht ziehe, dass ein String-Key auch mal '1234' lauten kann, wird es endgültig verrückt.
Da 1234=='1234' in PHP auf True evaluiert und array_merge nicht den Datentyp überprüft sondern einfach nur nachsieht ob der Key IRGENDWIE als Zahl interpretiert werden kann, werden Arrays mit String-Index von Array-Merge manchmal auch wie solche mit Zahl-Index verwendet.

Was soll das bringen? Hat hier irgendwer schonmal vor dem Problem gestanden dass er 2 assoziative Arrays mit String-Indices hat, von denen er gerne alle mit Text im String überschrieben bekommen hätte und alle bei denen nur Zahlen im Index stehen lieber angehängt bekommen möchte?

Oder mal aus Anwendungssicht: Stellen wir uns mal vor jemand schreibt eine Anwendung bei der die Objekte für einen Katalog gespeichert werden sollen. Der Einfachheit zuliebe schmeißen wir das also in ein assoziatives Array, bei dem der Key jeweils die Artikelnummer darstellt und die Value die Beschreibung enthällt. Jetzt erklärt mal euren Kunden, warum sie '12345678b' als Artikelnummer vergeben dürfen, das System sich aber die Nummer '12345678' irgendwie nicht merken kann!

Diese Funktionsweise ist nicht nur unsinnig und kontraintuitiv, sie ist auch dumm und gefährlich. Wirklich sinnvoll wäre gewesen die Werte bei gleichen Keys IMMER zu überschreiben, alles andere führt einfach nur zu unsinniger Funktionalität, die man beim Aufruf von array_merge nicht erwartet.
Ich bin ja immer dafür die eingebauten Funktionen zu verwenden, wenn schon aus keinem anderem Grund dann doch wenigstens weil diese meist schneller und besser optimiert sind als alles was man selbst schreibt oder weil man sich einfach nicht immer wieder damit abplagen will das Rad neu zu erfinden.
Hier sah ich jedoch keinen anderen Ausweg, vor allem da PHP einfach keine vernünftige Funktion anbietet.


function my_array_merge($array1, $array2)
{
foreach ($array1 as $key => $value)
{
$array2[$key] = $value;
}
return $array2;
}

Importierte/Alte Kommentare:

#1326: 20.Jan.2010 06:01 von Nox

full ack kann ich da nur sagen ...

Auch wenn dein Artikel schon etwas älter ist, er hat nix an Aktualität eingebüßt.

Ich bin diesem Problem erst vor ner Woche wieder begegnet, wunderte mich das ein Objekt zwar als Schlüssel '5' akzeptieren wollte, dann den Datensatz aber nicht unter '5' fand... array_merge hängt die numerischen Arrays nicht nur aneinander, nein, es erneuert auch die keys. Somit war aus dem Schlüssel '5' plötzlich die 0 geworden. Einfach herrlich.

Wenn du Spaß haben willst dann schau dir auch mal den '+' Operator für Arrays an ;)

Ciao
Nox

  • #1327: 20.Jan.2010 08:01 von Dr. Azrael Tod

    Von zu großen Dosen PHP bekomm ich immer wieder Übelkeit, Verstopfung UND Durchfall... alles Gleichzeitig! -.-

#1562: 20.Jan.2012 10:01 von Dr. Azrael Tod

Sehr schön finde ich auch die folgende "Lösung" um das doch einigermaßen mit mitgelieferten Funktionen zu machen:

$result = array_diff_key($a, $b) + $b

// example

$array1 = array(0 => 'zero_a', 2 => 'two_a', 3 => 'three_a');
$array2 = array(1 => 'one_b', 3 => 'three_b', 4 => 'four_b');

$result = array_diff_key($array1, $array2) + $array2;

//$result = array(
//  0 => 'zero_a'
//  2 => 'two_a'
//  1 => 'one_b'
//  3 => 'three_b'
//  4 => 'four_b')

:wall:

Geschrieben von Dr. Azrael Tod
Older article
T-Shirt-LIFO