Facebook
Twitter
Google+
Kommentare
7

MeinPHP: Typsicheres Set – Auflösung Teil 1

Heute ist es endlich soweit. Ich will anfangen, die erste Aufgabe von „MeinPHP“ aufzulösen. Naja auflösen ist vielleicht nicht der richtige Ausdruck, da es viele richtige Lösungen gibt und man auf keinen Fall etwas als falsch bezeichnen kann, das funktioniert. Ich will also unsere (Timo und meine) Lösung vorstellen und auf Schwächen eingehen, die wir bei den anderen Lösungen gefunden haben. Das ganze wird in drei Teile unterteilt. Im heutigen Teil werde ich die eingegangenen Lösung zeigen, die Schwachstellen und die guten Ideen ansprechen. Morgen werde ich einen Überblick auf Klassen- und Interfacebene geben und am Tag darauf die tatsächliche Implementierung. Ich muss natürlich dazu sagen, dass unsere Lösung nur subjektiv gut ist, ich denke es hängt immer vom Betrachter ab, ob einem der Stil gefällt, ich erwarte also auch Kritik eurerseits, wenn etwas nicht sauber gelöst ist.

Jetzt geht’s aber los mit der Übersicht über die Lösungen und meinen Kommentaren dazu:

  • Sebastian vom Milchtüten Blog
    Ich fange einfach mal mit der Lösung von Sebastian an, weil ich ihn am besten kenne und somit viel besser auf die Fehler eingehen kann, ohne einen Mordanschlag zu befürchten. Gut finde ich hier natürlich, dass er sich an eine bereits existierende Klasse der SPL hält: dem ArrayIterator. Dadurch wird das ganze schön schlank und natürlich auch Fehler unanfälliger. Es gefällt mir auch, dass die Klasse, die das Set halten soll, über den Konstruktor definiert wird. Wo auf jeden Fall ein Problem bei Sebastians Lösung besteht ist der „falsche“ Umgang der Klassenhierachien. Sobald ich eine Klasse B von Klasse A ableite, so ist die Klasse B auch vom Typ A und halt auch vom Typ B, denn nach außen bietet B alles, das auch A bietet und kann somit gleich behandelt werden. Aus diesem Grund sollte man auch mit der is_a Relation arbeiten und nicht über get_class und dann „==“, da man hier die Hierarchien nicht beachtet.
    Leider ist es auch nicht sehr performant, bei jedem hinzufügen alle bereits hinzugefügten Elemente durchzuiterieren, um zu prüfen, ob bereits im Set vorhanden ist. O(n) ist eher eine schlechte Komplexität, zu Zeiten von Hashtables O(1).
  • unset von PHP Hacker
    Bei unset findet man viele der soeben besprochenen Ansätze von Sebastian wieder, auch er hält sich an die SPL und auch er verwendet „==“ beim Vergleichen der Klassen. Eine Kleinigkeit noch, für die ich wohl einen Klugscheisserpunkt verdient haben werde, denn in einem Prototypen ist dies egal. Und zwar sollte man nie Standard Ausnahmen verwenden. Ich tippe mal drauf, dass beide im Produktivcode eine expliziete Exception genommen hätten, ich wollte es aber trotzdem loswerden.
    Was ich beim phphacker noch schön finde, ist, dass er Methoden verwendet, wenn dies möglich ist. Warum aber getType eine öffentliche Methode ist, weiß ich nicht. Ich kann mir eigentlich keinen Anwendungsfall vorstellen, in dem diese Methode verwendet werden kann.
    Unset ist leider nicht drauf eingegangen, dass ein Element höchsten einmal im Set sein darf.
  • Schwobeseggl
    Der erste der sich an das Set herangetraut hat ohne die SPL um Hilfe zu bitte. Muss ja nicht schlecht sein. Wobei ich Matthias doch raten würde ein wenig mehr auf private Methoden zu setzen, denn es macht es dem Leser einfacher durch den Code durchzusteigen. Aber wieder zurück, der Schwobeseggl hat sich dazu entschieden das ganze als Stapelspeicher zu implementieren, was natürlich allen gestellten Anforderungen entspricht. Anders als die anderen übergibt er den „Typ“ des Sets nicht im Konstruktor, sondern im macht es am ersten Element fest, das dem Set hinzugefügt wird. Ich bevorzuge, die Konstruktor Lösung, da ich zu einem späteren Zeitpunkt nie weiß, welches das erste Element ist. Wenn dieses schon verkehrt ist, so kann ich mir nicht sicher sein, warum ein Fehler auftritt, bzw. welches der Elemente falsch war.
    Die Reflection API zu bemühen ist natürlich auch eine nette Idee, aber in unserem Fall hätte auch ein get_class gereicht. Ich denke, dass es über get_class weniger kostet und außerdem ist es nur ein Befehl statt mehrerer. Auch befinden wir uns wieder in O(n) in unserer Komplexität.
    Auch von der Verwendung von gettype( ) rät php.net ab, wenn man es dazu verwendet um auf einen bestimmten Typ zu prüfen, da sich die Zeichenkette in späteren Versionen von PHP ändern kann. Ich finde die Lösung vom Schwobeseggl aber auf keinen Fall schlecht, sie macht das was es machen soll.
  • Schaelle
    Auch hier wunderbar gemacht. Einfach an die SPL gehalten und alles Methoden schön kommentiert. Leider kann man hier nur primitive Typen, wie String oder Bool reinpacken. Spannender wird es natürlich bei Objekten. Martin arbeitet bei der Prüfung, ob ein Element im Set enthalten ist aber auch über ein foreach, was wieder zu O(n). Ich mags aber, dass Schaelle klar nach dem Motto „Separation of Concerns“ arbeitet und ein neues Objekt zur Verfügung stellt, dass ein Set Element representiert.
    Die Liste mit den ganzen is_bool( ) || is_string( )... hätte er wohl ein wenig einfacher hinbekommen können über ein !( is_array( ) || is_object( ) ).  Leider verstehe ich nicht, warum er sein Set nur auf primitive Typen beschränkt hat, denn soweit ich das erkennen kann hängt es nur am Hashwert für ein Objekt. Und dafür bringt ja PHP schon Hausmittel mit.
    Leider finde ich auch nicht die Stelle, wo er prüft, ob die Typsicherheit gegeben ist, aber ansonsten auf jeden Fall eine nette Lösung.
  • Andy G.
    Andy hat mir seine Lösung per E-Mail zugeschickt. Nett hierbei finde ich, dass Andy alle Grundfunktionalität in eine abstrakte Klasse gepackt hat und dann diverse Klassen abgeleitet. Da schlägt doch das OOP Herz höher. Leider gibt es auch hier keine Implementierung, die es ermöglicht Objekte zur Menge hinzufügen. Die compareTwoValues Methoden sind meiner Meinung nach alle ein wenig umständlich gelöst. Ein return $value1 === $value2; hätte z.B. im intSet völlig ausgereicht.
    Ansonsten denke ich, dass auch die Lösung von Andy nicht schlecht ist, nur fände ich es besser, wenn er die ganzen casts weglassen und dafür exceptions werfen würde.

So das waren auch schon die fünf Lösungen, die bei mir eingegangen sind. Von Axel, der eine PHP Erweiterung schreiben wollte, habe ich bereits die Absage bekommen, dass er leider keine Zeit finden wird. Auch Lars Jankowfsky tut es Leid.
Ich würde mich übrigens sehr freuen, wenn ihr euch auch die diversen Lösungen mal anschaut und mir eure Meinung dazu sagt. Ansonsten würde ich sagen stelle ich morgen einfach die Lösung von Timo und mir vor.

Über den Autor

Nils Langner

Nils Langner ist der Gründer von "the web hates me" und auch der Hauptautor. Im wahren Leben leitet er das Qualitätsmanagementteam im Gruner+Jahr-Digitalbereich und ist somit für Seiten wie stern.de, eltern.de und gala.de aus Qualitätssicht verantwortlich. Nils schreibt seit den Anfängen von phphatesme, welches er ebenfalls gegründet hat, nicht nur für diverse Blogs, sondern auch für Fachmagazine, wie das PHP Magazin, die t3n, die c't oder die iX. Nebenbei ist er noch ein gern gesehener Sprecher auf Konferenzen. Herr Langner schreibt die Texte über sich gerne in der dritten Form.
Kommentare

7 Comments

  1. Quote: „Die Liste mit den ganzen is_bool( ) || is_string( )… hätte er wohl ein wenig einfacher hinbekommen können über ein !( is_array( ) || is_object( ) ).“

    resourcen auch nicht vergessen und dann ist es noch einfacher is_scalar() benutzen:
    http://de3.php.net/is_scalar

    Reply
  2. ja danke dir für die ganze beitragsreihe. es kommen doch immer eine menge interessante aspekte zusammen und es ist sehr anregend, wenn es auch noch redaktionell aufbereitet wird.

    Reply

Leave a Comment.

Link erfolgreich vorgeschlagen.

Vielen Dank, dass du einen Link vorgeschlagen hast. Wir werden ihn sobald wie möglich prüfen. Schließen