Facebook
Twitter
Google+
Kommentare
13

phm-0: Benamung von Klassen

Ich habe ja vor ein paar Wochen den psr-0 vorgstellt, einem Standard, der vorschreibt, wie man Namespaces auf Verzeichnisse abbildet. Standardisierung ist ja immer ein wunderbare Idee, da wo man mehrere Leute hat, die eigentlich genau das gleiche machen. Jetzt war ich heute auf der Webseite von Stephan Hochdörfer und dort wurde ein wenig über die Standardisierung einer Dependance Injection-Schnittstelle geredet. Ich glaube aber, das man dort noch nicht so weit ist, dass man schon von einem Standard reden kann. Auf jeden Fall ist Standardisierung angesagt und da will ich dann natürlich auch mitmischen. Erstmal nur mit einem RFC (Request for Comments), auf den ihr dann eure Meinung loslassen könnt.

Erstmal müssen wir natürlich definieren, was wir standardisieren wollen. Es geht um die Benamung von Klassen und den dazugehörigen Namensraum. beschränken möchte ich das erstmal auf Bibliotheken (ich habe das Gefühl, dass bei Applikationen andere Regeln gelten können). Ich würde das ganze einfach einmal mit einer gewöhnlichen Klasse durchdenken und danach Regeln daraus ableiten.

Die Klasse, die wir nutzen ist ein einfacher Http-Request. Dabei werden wir ein Request-Interface definieren und eine dazugehörige Implementierung, die auf cUrl aufbaut. Gehen wir einfach mal davon aus, dass dies eine sinnige Aufteilung ist. Zuerst einmal brauchen wir den Namensraum. In diesem Fall finde ich es eindeutig, dass es in den Http-Raum gehört. Jetzt wird es aber tricky, zumindest werden sich jetzt die Geister scheiden. Ich bin dafür, dass der Raum noch ein wenig genauer spezifiziert wird, so dass alle Klassen und Interfaces, die Teil des Request sind unter Http/Request liegen. Das Request-Interface würde somit unter Http/Request/Request liegen. Das Zend Framework würde dies anders definieren, finde ich so aber sauberer.

Ohne was zu sagen, habe ich schon wieder die nächste Konvention eingeführt. Interfaces haben keine gesonderte Auszeichnung. Ganz nach Clean Code von Onkel Bob. Möglich wären auch RequestInterface oder iRequest, aber irgendwie fahre ich gut, mit dem Weglassen. Zusätzlich liegen die Interfaces immer dort, wo auch die konkreten Implementierungen liegen. Bastian Feder hat im PHP Powerworkshop eine andere Konvention eingeführt (Interfaces liegen in einem Interface-Namespace), aber mit dieser bin ich nicht einverstanden.

Definieren wir also schon mal für diese Fälle die Regeln.

  • psr-0 gilt das Mapping von Klassen und Dateien
  • Klassen liegen immer in dem Namensraum, in dem die Gruppe der dazugehörigen Klassen liegt
  • Interfaces liegen dort wo auch die konkreten Implementierungen liegen
  • Interfaces haben keine gesonderte Auszeichnung und werden behandelt wie Klassen

Wie es mit der Benennung der eigentlichen Klassen aussieht würde ich morgen definieren, da für heute schon genug Ideen gesammelt wurden, die man ja schon mal besprechen kann.

Ü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

13 Comments

  1. Wie sieht es mit dem Vendor-Name aus? psr-0 erfordert, dass alle Namespaces mit einem Vendor-Prefix anfangen
    „Each namespace must have a top-level namespace („Vendor Name“).“

    Da es sich um eine Bibliothek handeln soll ist das erst recht wichtig, und „Http“ ist in diesem Fall nicht unbedingt ein Sinnvoller top-level namespace 😉

    Reply
  2. Sowohl Patrick als auch Thomas muss ich zustimmen.

    Was mich stört, sind doppelte Bezeichnungen in Klassennamen. Ist doch eher verwirrend, statt dass es hilft. Was ist, wenn man noch eine abstrakte Request-Klasse benötigt? Also ich finde, dass alles, was keine reale Klasse ist, ein Suffix im Namen tragen sollten. Bsp.: Vendor\Http\Request\RequestInterface oder Vendor\Http\Request\RequestAbstract.

    Aber wie gesagt, eigentlich nichts neues erfinden, sondern vorhandene Standards adaptieren.

    Reply
  3. @René: Das hat nichts mit neu erfinden zu tun. In Clean Code wird empfohlen, es ohne den Suffix bzw. Prefix Interface zu machen und das ist ein Standardwerk.

    Aber ich habe den Artikel ja zum Diskutieren erstellt, wenn mehr Leute denken, man sollte es prefixen und die Gründe dafür gut sind, dann sollte man es auch tun.

    Reply
  4. Genau, zum Diskutieren habe ich auch einfach mal meinen Kommentar abgegeben.

    Nach einer kurzen Diskussion mit einem Kollegen sind wir der Meinung, dass adjektivierte Namen für Interfaces sehr sinnvoll sind. In diesem speziellen Beispiel wäre es dann \Vendor\Http\Request\Requestable, was natürlich sehr sinnfrei klingt. Aber es gibt bestimmt bessere Lösungen.

    Bei abstrakten Klassen bin ich mir nicht sicher, ob man das Suffix „Abstract“ verwenden soll, oder es einfach weg lässt. Denn letztlich ist eine abstrakte Klasse auch eine Klasse. Wenn es also eine abstrakte Request-Klasse gibt, dann könnte die einfach nur \Vendor\Http\Request heißen.

    Reply
  5. Die Webseite nennt man einen „Blog“ 🙂 – Muss dir (und anderen) natürlich recht geben, bevor man anfängt DIC zu standardisieren sollte man bei den Basics anfangen. Mir war zu dem Zeitpunkt nur aufgefallen dass viele der großen Frameworks mittlerweile DIC machen wollen ohne zu überlegen ob es nicht vielleicht auch Sinn macht die DIC Komponente selbst austauschbar zu gestalten.

    Reply
  6. Moin! Ich finde es auch nicht gut, Interfaces und Abstrakte mit Prefixes o.ä, zu versehen. Eher würd ich sagen, packt den Prefix in den Namensraum-Pfad. Anhand des Beispiels sähe meine Lösung so aus:

    PHP:
    namespace Vendor\Request;
    use \Vendor\Request\Abstracts\Request;
    use \Vendor\Request\Interfaces\EmulatesCUrl;
    use \Vendor\Request\Interfaces\ProvidesRemoteAccess;
    use \Vendor\Request\Interfaces\HasClient;
    use \Vendor\Request\Interfaces\MayBeAsynchronous;
    use \Vendor\Request\Exceptions\RuntimeException;
    use \Vendor\Request\Results\ArrayObject;
    use \Vendor\Request\Results\ArrayObjects\Json;
    use \Vendor\Request\Results\ArrayObjects\Xml;

    class Ajax extends Request
    implements ProvidesRemoteAccess, MayBeAsynchronous, etc
    {}
    /PHP

    Mein Grundgedanke: Benennt Abstrakte Klassen danach, was sie SIND (also abbilden) und Interfaces danach, was ihre Methoden BIETEN, HABEN oder KÖNNEN etc. Was ich schön finde: Alles was zusammengehört steckt in einem Koffer, und ich kann bei kleineren Bausteinen generische Namen verwenden (ArrayObject).

    Grüße

    Reply
  7. @Renè: Mit dem Adjektivieren komme ich gar nicht klar als allgemeine Regel. Ich würde hier wirklich unterscheiden, was das Interface macht. Beschreibt es eine ganze Klasse oder Eigenschaften einer solchen. Für mich wäre es immer Request, aber Countable oder Comparable. Ich glaube da macht die natürliche Sprache auch gar nicht mit. Was ist denn das Interface, das einen Baum beschreibt? Treeable? Baumbar gefällt mir aber irgendwie.

    @Carsten: Deins muss ich erstmal verstehen, dann melde ich mich wieder.

    Reply
  8. @Carsten: Bei dir sehe ich das Problem, wenn ich mal zwei der Interfaces benötige um mit einem Objekt hantieren zu können. Typehinting funktioniert halt nicht mit mehreren Interfaces. Natürlich hat man das Problem auch so, aber halt nicht so oft, da die Interfaces größer gefasst sind.

    Reply
  9. Für mich klingen alle Lösungsansätze viel zu kompliziert. Ich halte mich, wie Patrick schon vorgeschlagen, einfach an die Java Conventions.

    Beispiel: https://github.com/akkie/mohiva-framework/tree/master/src/com/mohiva/framework/cache/adapters

    Das Interface „Adapter“ beschreibt die Schnittstelle. Dann gibt es verschiedene Implementierungen.

    com\mohiva\framework\cache\adapters\Adapter -> Interface
    com\mohiva\framework\cache\adapters\APCAdapter -> Konkrete Implementierung
    com\mohiva\framework\cache\adapters\ResourceAdapter -> Konkrete Implementierung

    Die konkrete Implementierung sollte immer den Namen des Interfaces im Namen beinhalten.

    Eine gute Übersicht findet sich auch hier:
    https://github.com/akkie/mohiva-framework/tree/master/src/com/mohiva/framework/core/io

    Des weiteren verstehe ich auch nicht wieso, die Benennung von Klassen und den dazugehörigen Namensraum, für die Standardisierung eines DIC wichtig sein soll. Solange alles PSR-0 konform ist sollte ein standardisierter DIC jede Klasse, egal nach welcher Konvention die Benennung oder die Anordnung/Schachtelung der Verzeichnisse/Dateien vorgenommen wurde, laden können.

    Reply
  10. @Nils: Du meinst sicher, wenn eine Methode ein Objekt erwartet, das zwei der Interfaces implementieren muss.

    Auf das Problem bin ich auch gestoßen. Ich mach das so: In den Methoden, die in einem bestimmten Interface vorgeschrieben sind, versuche ich, nach Möglichkeit nur mit den jeweils „eigenen“ Methoden auszukommen. Dann ist das Typehinting ausreichend. – Komme ich dagegen nicht drumherum, innerhalb der Methoden andere Methoden aus einem anderen Interface zu verwenden, „typehinte“ ich nicht auf die Instanz eines Interfaces, sondern auf eine konkrete Instanz der Abstrakten bzw. auf die konkrete Klasse selbst.

    Hast aber recht, es ist eine eigenwillige Denkweise – für mich überwiegt aber der sehr deluxige Vorteil, dass ich schon nach der Lektüre der Use-Statements und der Klassenkopfes rein verbal informiert bin, was das Teil macht/kann/darf/bietet.
    –Grüße

    Reply
  11. @Christian die Benennung von Klassen hat nichts mit DIC Standardisierung zu tun. Nils hat das nur als Beispiel aufgegriffen. Mir geht es auch nicht darum Namenskonventionen für DIC einzuführen sondern das generelle Verhalten eines Containers zu definieren damit dieser austauschbar ist.

    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