Heute fragte mich jemand, ob ich eigentlich etwas kennen würde, um mit PHP „schöner“ zu programmieren. Ich dachte zugegebener Maßen erst an einen Editor (da würde ich PhpStorm (gibt’s für Studenten umsonst!) empfehlen), es wurde dann aber relativ schnell klar, das es eher um sowas wie ein PHP-Framework geht. Um es gleich mal klar zu sagen: Ohne irgendein Framework würde ich nichts in PHP schreiben, was länger als 100 Zeilen ist. Man muss das Rad ja nicht immer neu erfinden, und dabei die gleichen Sicherheitslücken wieder einbauen 🙂
Nun entwickele ich für meinen Hiwi-Job schon rund 4 Jahre in PHP. Dabei habe ich die erste Zeit eine Anwendung weiter gepflegt, die ohne ein Framework geschrieben war. Nach einiger Zeit war klar, das es so nicht weitergehen konnte, die Anwendung war, auch durch ihr Alter und die Weiterentwicklung von PHP, unwartbar geworden und lief mit schnellen Schritten auf das End-Of-Life „ihrer“ PHP-Version zu. (Mehr sage ich jetzt nicht, der Autor ließt hier mit 🙂 ). Es musste also eine Neuentwicklung her, natürlich auf Basis eines Frameworks. Damals wurde mir CakePHP empfohlen (damals noch Version 2), was ich dann relativ unreflektiert übernommen habe. Jetzt nähert sich die Anwendung langsam der Fertigstellung, inzwischen basierend auf CakePHP 3. Im Laufe der Entwicklung hat sich eine gewisse Hassliebe zu Cake entwickelt…
Die Frage, ob ich CakePHP als Framework empfehlen kann, ist also nicht ganz einfach zu beantworten. Da ich heute nur eine kurze Antwort geben konnte, soll dieser Blogeintrag sich der Frage noch mal etwas ausführlicher nähern. Für alle anderen ist das einfach nur ein Review zu CakePHP.
CakePHP ist nun also ein PHP-Framework, wie es viele gibt. Es ist also ein Sammlung von Code, der es einfacher macht, mit PHP (Web-)Anwendungen zu schreiben. Dazu muss man vielleicht auch sagen, das PHP keine besonders tolle Sprache ist. Sie ist quasi auf jedem Webhost verfügbar, aber das Design der Sprache ist doch recht schlecht. Ihren ursprünglichen Ansatz, eine „kleine“ Scriptsprache für Webseiten zu sein, hat sie längst hinter sich gelassen, inzwischen will sie eine „große“ Programmiersprache sein, aber so ganz kann sie ihre Altlasten auch mit PHP 7 nicht abwerfen. PHP-Frameworks stehen daher in einer gewissen Sonderrolle: In anderen Programmiersprachen besteht oft die Herausforderung darin, überhaupt „das Web in die Sprache“ zu bringen, also Dinge wie die Interaktion mit einen Webserver. Bei PHP ist das alles vorhanden und irgendwie fest in der Sprache verwurzelt (man kann mit PHP irgendwie auch nichts anderes als Webseiten bauen…), hier geht es leider (auch) darum, das schlechte Design der Sprache zu verstecken und die vorhandene Anbindung in schönere Formen zu bringen. Eine einfache Website mit Datenbankanbindung ist in PHP schnell und ohne jedes Framework gebaut, etwas was in anderen Sprachen gar nicht möglich ist. Das sind Dinge, die PHP-Frameworks immer so ein bisschen besonders machen.
Nach dieser langen Vorrede noch schnell ein kleiner Disclaimer, dann soll es auch endlich um Cake gehen: Ich habe, wie oben geschrieben, mich damals relativ spontan für Cake entschieden. Ich habe seit her kein anderes Framework angefasst. Ich kann also keine Vergleiche ziehen, ich kann nur meine Erfahrungen mit Cake beschreiben. Ich weiß nicht, ob andere es besser machen 🙂
The good parts
Was macht CakePHP gut? Das Rapid-Prototyping. Es gibt eine Konsolenanwendung namens „bake“, die automatisch aus einer Datenbankstruktur (sofern sie denn den Konventionen von Cake entspricht, die aber generellsinnvoll sind), automatisch eine komplette Anwendung (oder auch nur Teile davon) generieren kann. Hier bekommt man sofort die Möglichkeit, Records in der Datenbank anzulegen, zu bearbeiten und zu löschen, es gibt automatische Verknüpfungen zu verbundenen Tabellen, passende Fehlermeldungen und Datenvalidierung. Wenn es im Wesentlichen um eine kleine Anwendung geht, mit der man Einträge in einer Datenbank bearbeitet, ist man mit Cake wirklich in 5 min fertig. Die generierte Anwendung hat sogar ein akzeptables Design 🙂 Der Code der generiert wird, entspricht dem, den man sowieso schreiben müsste, und lässt sich auch recht leicht an eigene Bedürfnisse anpassen. Wenn man dann noch nach dem Tutorial eine Benutzerverwaltung hinzufügt hat man wirklich eine schlüsselfertige Anwendung. Das System was ich baue, ist doch um ein paar Ecken komplexer, aber es basiert auch auf Code, der von bake generiert wurde.
Den Datenbankzugriff. Cake hat einen recht schönen ORM-Layer, der es einfach macht, ein paar Objekte inklusive der Abhängigkeiten (ein Benutzer mit all seinen Kommentaren) aus der Datenbank zu holen. Auch das Speichern ist recht einfach (siehe aber auch unten), und das System schützt einen vor SQL-Injection-Lücken. Gerade bei komplexeren Joins ist das wirklich eine große Erleichterung. Außerdem bekommt man immer Objekte des passenden Model-Typs von ORM-Layer zurück, und nicht nur die rohen Daten (eine große Verbesserung zu CakePHP 2!).
…und tja, damit ist die Liste hier irgendwie auch schon wieder zu Ende. Cake macht noch eine Menge Dinge akzeptabel, sie funktionieren einfach. Routing. HTML-Erzeugung. Erweiterbarkeit. Jede Menge praktische Funktionen. Hohe Testabdeckung. API-Dokumentation. Aber das sind alles Dinge, die toll sind, wenn man bis her ohne Framework gearbeitet hat, aber nichts, was einen vom Hocker haut, oder wo ich von Cake beeindruckt gewesen wäre.
Die Schattenseiten
Was macht Cake also schlecht, warum kann ich es nicht uneingeschränkt empfehlen? Tja, das ist, wie gesagt, eine schwierige Frage. Ich denke, am besten beschreiben es die Phrasen „Undurchsichtigkeit des Kern“ und „magische Kopplung“, gepaart mit nicht so toller Dokumentation. Ja, es gibt eine API-Dokumentation und auch das Kochbuch. Das zusammen ist wirklich viel Dokumentation, und sie ist auch gut geschrieben. Das große Problem ist, das sie viel zu sehr an der Oberfläche bleibt. Es gibt zwar für jedes Feature Codebeispiele und Erklärungen, und wenn man es noch genau wissen will, findet man auch zu quasi jeder Funktion einen Unit-Test. Das Framework ist wunderbar aus kleinen Teilen aufgebaut, die alle unabhängig von einander sind, ganz so, wie man es machen soll. Leider vermag die Dokumentation überhaupt nicht zu vermitteln, wie die einzelnen Teile zusammenarbeiten. Es gibt ein paar Tutorials, die einem zeigen, wie man eine einfache Webanwendung baut, und auch dem Code, den bake generiert, kann man den Grundaufbau entnehmen, in dem viele Teile automatisch gut zusammenspielen. Es fehlt aber an Beschreibung, an welchen Stellen man ansetzen kann, wie man mehr macht als nur eine kleine CRUD-Anwendung.
Wie oft habe ich schon davon gestanden, und mich gefragt, an welcher Stelle es wohl vorgesehen ist, eine bestimmte Sache einzubauen. Leider ist oft die Antwort „mach es, wie du es für richtig hälst“. Wenn man begriffen hat, das CakePHP eigentlich nur eine Sammlung von einzelnen Komponenten ist, die eigentlich nicht so besonders viel miteinander zu tun haben, kommt man klar. Gerade am Anfang hat man aber immer das Gefühl, das da „mehr“ sein müsste. Ein übergeordnetes System, was alles zusammenhält. So etwas gibt es aber einfach nicht. Die Modularität ist sicher eine der Stärken von Cake, aber sie ist schwer zu nutzen, weil die ganzen internen Zusammenhänge nur wenig dokumentiert sind. So erzeugt der HTML-Helper zufälligerweise Formulare, die genau so strukturiert sind, wie es später der ORM-Layer erwartet. Ich habe lange Zeit gedacht, man müsste daher alles über den HTML-Helper machen. Es gibt aber keine „magische“ Verbindung zwischen diesen Komponenten, der ORM-Layer verdaut auch hand(oder JavaScript-)gestrikte Formulare ohne Probleme.
So ist Cake an vielen Stellen: Die eine Komponente tut Dinge, die genau zu einer anderen passen. Der Austausch dazwischen erfolgt aber in einem einfachen Format, und das kann man auch problemlos auf andere Art und Weise generieren. Genauso sind die meisten Systeme relativ „dumm“ und erzeugen, wenn man ihnen entsprechende Daten gibt, auch Ausgaben, die nicht mehr zu der anderen Komponete passen. Auf diese Weise hat man immer, wenn man eine Erweiterung des Kern-Systems baut, so leicht das Gefühl, einen Hack zu schreiben. Oft ist es aber genau so gedacht. Das ist leider etwas, was die Dokumentation überhaupt nicht vermitteln kann. Auch interne Abläufe z.B. des ORM-Systems sind nicht dokumentiert, daher ist es nicht einfach, dort zu debuggen, um zu verstehen, wie Code funktioniert.
Schlussendlich ist dieses „alles ist irgendwie so halb ein Hack“ auch etwas, was PHP ausmacht. So kennt Cake auch für fast jede Funktion ein „$options“-Array, wo man ein assoziatives Array mit weiteren Optionen reinpacken kann. Welche Schlüssel in der Funktion etwas tun, muss man der Dokumentation entnehmen. Oder der Doku der Funktion, die intern verwendet wird, denn oft wandert dieses Array auch gleich an diese Funktion weiter. Zusammen mit der nicht besonders strengen Typisierung in PHP ist das vermutlich idomatisch, aber leider nicht praktisch. Ohne einen gute Editor mit einem Shortcut für „Show PhpDoc“ ist man hier verloren. Und selbst PhpStorm ist schnell verwirrt und weiß nicht mehr, welchen Typ ein Objekt haben kann, viele Funktionen geben mixed, also jeden Typ, zurück. Was man wirklich bekommt, hängt dann oft von den Parametern ab.
Und nun?
Würde ich CakePHP denn nun als empfehlen? Wenn es PHP sein muss: Ja. Schon aus dem Fakt heraus, das ich kein anderes Framework kenne, und es nicht so schlecht ist, das ich nur davon abraten kann. Man kommt damit schnell zu einem Ergebnis, das oft eigentlich auch schon reicht. Man kommt auch noch ein bisschen weiter, aber wenn man dann doch etwas mehr als nur CRUD haben will, dann schlägt eine sehr steile Lernkurve zu, an deren Ende oft das Ergebnis steht, das es keine offiziellen Weg gibt, dies oder jedes zu tun, man baut einfach etwas, das funktioniert.
Ich habe natürlich auch immer mal wieder ein bisschen über den Tellerrand geschaut, und bei anderen PHP-Frameworks sieht manches ein bisschen besser aus, und nicht zuletzt haben sie ja auch eine weitere Verbreitung als Cake gefunden. Inzwischen habe ich aber meinen Frieden mit Cake geschlossen.
Und wenn es nicht PHP sein muss? Dann würde ich blindlings zu ASP.NET raten. Mit C# steckt eine großartige Sprache dahinter, es läuft dank .Net Core auf Linux (offiziell, ohne Mono!), und was ich bis jetzt davon gesehen habe, sah großartig aus. Aber manchmal muss es eben PHP sein 🙂