(Meinung) Klasseninstanz in Template
hotti
- php
0 mrjerk
hi,
s. Thema. Bei Magento ist es üblich, dass in der TemplateDatei (.phtml) mit der Klasseninstanz gearbeitet wird, z.B.: <?php echo $this->getArticleSize() ?>
. Ein mMn strittiges Thema: Es wird direkt auf ein Attribut zugegriffen, z.B. so:
<pre> <?php echo print_r($this->dBase_Article->article(),1) ?> </pre>
// neues Attribut ^ ^
Mein Attribut 'dBase_Article' ist eine Instanz der Klasse 'dBase_Article' und wird über magic Method '__get(Access to inaccessible properties)' zur Laufzeit geschaffen, was dann den Methodenaufruf ermöglicht. Ist das (in der Templatedatei) OK, oder verstößt das gegen OOP-Grundsätze?
Hotti
Hallo,
Mein Attribut 'dBase_Article' ist eine Instanz der Klasse 'dBase_Article' und wird über magic Method '__get(Access to inaccessible properties)' zur Laufzeit geschaffen, was dann den Methodenaufruf ermöglicht. Ist das (in der Templatedatei) OK, oder verstößt das gegen OOP-Grundsätze?
Also, ich verwende grundsätzlich ausschliesslich Getter und Setter um auf Instanz-Variablen zuzugreifen und nie Direkt-Zugriff.
Das liegt aber mehr an meiner eignen Arbeitsweise: Wenn ich für jede Instanz-Variable, die ich ausserhalb ändern/benutzen will einen Setter/Getter implementieren MUSS (und sei es auch nur, dass ich in Eclipse auf "Generate Getters/Setters" klicken muss :)), zwingt mich das dazu, mir genauer zu überlegen, welche Variablen nach aussen hin denn wirklich interessant /notwendig sind (und welche ich lieber "private" lasse, da andere Klassen daran eh nicht herumzufummeln haben).
Soweit ich weiss, ist das auch "schöner" Programmierstil (ich meine mich zu erinnern, dass es in Java auch ein paar unangenehme Absonderlichkeiten gibt, wenn man z.b. Instanzvariablen mit primitive Datentypen von aussen direkt, also ohne Zugriff mittels Setters, ändert).
Eine technisch fundierte Begründung kann ich aber leider nicht liefern :)
Viele Grüße,
Jörg
Tach!
Also, ich verwende grundsätzlich ausschliesslich Getter und Setter um auf Instanz-Variablen zuzugreifen und nie Direkt-Zugriff. Das liegt aber mehr an meiner eignen Arbeitsweise: Wenn ich für jede Instanz-Variable, die ich ausserhalb ändern/benutzen will einen Setter/Getter implementieren MUSS [...], zwingt mich das dazu, mir genauer zu überlegen, welche Variablen nach aussen hin denn wirklich interessant /notwendig sind (und welche ich lieber "private" lasse, da andere Klassen daran eh nicht herumzufummeln haben).
Und warum kannst du diese Überlegungen nicht beim Notieren des Sichtbarkeits-Keywords anstellen? Reine Getter/Setter ohne weitere Funktionalität verbraten (geschätzt) mindestens doppelt so viel Zeit wie ein einfacher Zugriff.
Statt einer Zuweisung (mit Nebenhandlungen wie Variablennamenauflösung) hast du zwei Zuweisungen und einen Funktionsaufruf. Beim Lesen ungefähr daselbe.
Der Zeitverbrauch mag bei kleinen Projekten keine Rolle spielen, aber bei vielen Zugriffen läppert sich das ganz schön zusammen.
Soweit ich weiss, ist das auch "schöner" Programmierstil (ich meine mich zu erinnern, dass es in Java auch ein paar unangenehme Absonderlichkeiten gibt, wenn man z.b. Instanzvariablen mit primitive Datentypen von aussen direkt, also ohne Zugriff mittels Setters, ändert).
In Java ist es eine Konvention mangels besserer Möglichkeiten dieser Sprache. Es gibt einige Frameworks/whatever, die auf die Benennung get.../set... reagieren oder anderweitig darauf angewiesen sind, um richtig zu funktionieren. Diese Notwendigkeit ist mir von PHP her nicht bekannt. Nicht alles was anderswo gang und gäbe ist, muss für PHP genauso sinnvoll sein.
dedlfix.
Hallo,
Statt einer Zuweisung (mit Nebenhandlungen wie Variablennamenauflösung) hast du zwei Zuweisungen und einen Funktionsaufruf. Beim Lesen ungefähr daselbe.
Ok, Ack
Der Zeitverbrauch mag bei kleinen Projekten keine Rolle spielen, aber bei vielen Zugriffen läppert sich das ganz schön zusammen.
Ich wage zu bezweifeln, dass so etwas tatsächlich ernsthaft ins Gewicht fällt.
Ich habe es bisher noch bei keiner PHP-Anwendung erlebt, dass der Bottlenck tatsächlich CPU-Zeit war - wenn ich eine Anwendung fixen/optimieren musste, die performancemässig im Keller war, war so gut wie immer ein lausiges Datenbank-Design, nicht-optimierte SQL-Statements, unnötige IO, zu viel Arbeitsspeicher-Verbrauch uvm. schuld.
Der Performance-Gewinn, der durch Caching, clevere Datenbankschichten, Vermeidung unnötiger IO uvm. möglich ist, ist um Welten größer als das, was man durch die Einsparung des Overheads an CPU-Zyklen spart.
Es mag sein, dass auf embedded Systemen o.ä., wo man wirklich mit begrenzten Resourcen auskommen muss oder bei sehr rechenintensiven Prozessen tatsächlich Probleme bekommt. In diesem Fall ist PHP aber vermutlich eh nicht Mittel der Wahl als Programmiersprache.
Wenn es die Übersichtlichkeit/Wartbarkeit des Codes erhöht, würde ich einen solch geringen Performance-Verlust in jedem Fall in Kauf nehmen. Allerdings gebe ich zu, dass man über die Frage, ob durch den Einsatz von Gettern/Settern tatsächlich die Übersichtlichkeit erhöht wird, sicher vortrefflich streiten kann.
In Java ist es eine Konvention mangels besserer Möglichkeiten dieser Sprache. Es gibt einige Frameworks/whatever, die auf die Benennung get.../set... reagieren oder anderweitig darauf angewiesen sind, um richtig zu funktionieren. Diese Notwendigkeit ist mir von PHP her nicht bekannt.
Naja, Symfony2 nutzt z.b. diese Mechanismen sehr exzessiv (sowohl in der Datenbankschicht, also der "Doctrine"-Welt, als auch bei der Template-Engine Twig). Ich mag mich täuschen, aber ich glaube bei Zend gibt es auch solche Konventionen.
Tach!
Wenn es die Übersichtlichkeit/Wartbarkeit des Codes erhöht, würde ich einen solch geringen Performance-Verlust in jedem Fall in Kauf nehmen. Allerdings gebe ich zu, dass man über die Frage, ob durch den Einsatz von Gettern/Settern tatsächlich die Übersichtlichkeit erhöht wird, sicher vortrefflich streiten kann.
Jede Menge Methoden, die nichts weiter tun, als einen Wert aus einer Variable zu lesen oder ihn dorthin zu schreiben, pflastern die Code-Dateien nur unnötig voll. Ohne Erfahrung, welche Getter/Setter man unbeachtet lassen kann und welcher doch mal etwas anders macht, verfolgst du im Debugfall jeden einzelnen dieser sinnlosen Methodenaufrufe, um dann entnervt die eine Methode zu übersehen, die anders ist. Durch solchen einen Code-Wust in der Klassendatei zu navigieren ist auch keine Freude, zumal die Methoden selten nach dem Informationsgehalt für Code-Leser sondern eher nach Alphabet sortiert sind.
Da lob ich mir doch C#, das hat Propertys mit eingebauter Getter/Setter-Funktionalität. Wenn man keine Extrawurst braucht, gestattet da bereits die Syntax das Weglassen der Metoden-Notation (intern wird das zu Methoden umgesetzt, aber das tangiert die Übersichtlichkeit des Codes nicht). Diese Propertys sind genauso einfach handzuhaben wie einfache Fields und bei Bedarf bekommt auch der restliche Code von einer Erweiterung nichts mit - es bleibt augenscheinlich ein Eigenschaften-Zugriff. Wenn man in PHP und Java von Eigenschaft auf Methodenaufruf wechseln möchte, muss man das an den aufrufenden Stellen anpassen, wenn man nicht im vorauseilendem Gehorsam sowieso alles mit Gettern/Settern versehen hat. Zumindest bei PHP kann man hier mit der __get/__set-Magie einen guten Kompromiss zwischen Übersichtlichkeit und eventuell doch mal benötigter Funktionalität eingehen.
dedlfix.
hi,
Wenn es die Übersichtlichkeit/Wartbarkeit des Codes erhöht, würde ich einen solch geringen Performance-Verlust in jedem Fall in Kauf nehmen. Allerdings gebe ich zu, dass man über die Frage, ob durch den Einsatz von Gettern/Settern tatsächlich die Übersichtlichkeit erhöht wird, sicher vortrefflich streiten kann.
Ja ;)
Hier eine meiner Ideen:
Methode 'eav': Entity (Response), Attribute, Value
// $this ist die Instanz der Controller-Klasse (Response Class in meinem FW)
$this->eav('title'); // gib mir mal den Titel
$this->eav('title', 'Neuer Titel für die Seite'); // geht zur Laufzeit
$this->eav('title', $this->eav('title')." Anhängsel"); // geht auch
In Java ist es eine Konvention mangels besserer Möglichkeiten dieser Sprache. Es gibt einige Frameworks/whatever, die auf die Benennung get.../set... reagieren oder anderweitig darauf angewiesen sind, um richtig zu funktionieren. Diese Notwendigkeit ist mir von PHP her nicht bekannt.
Zuviel Voodo ;) Ein Kollege sagte mal: Einen Getter/Setter würde ich niemals einen Namen geben, der mit get/set anfängt...
Naja, Symfony2 nutzt z.b. diese Mechanismen sehr exzessiv (sowohl in der Datenbankschicht, also der "Doctrine"-Welt, als auch bei der Template-Engine Twig). Ich mag mich täuschen, aber ich glaube bei Zend gibt es auch solche Konventionen.
...dabei ging es um Magento (Zend).
Ich finde, jeder darf die Magic-Methods sooo mißbrauchen, wie er das für gut befindet. PHP __call() missbrauche ich z.B. für Methoden, die aufgrund ihrer Zeilenzahl die Code-Struktur einer Controller-Klasse optisch versauen würden: Ab damit ins Dateisystem ;)
Hotti
Moin mrjerk,
Soweit ich weiss, ist das auch "schöner" Programmierstil (ich meine mich zu erinnern, dass es in Java auch ein paar unangenehme Absonderlichkeiten gibt, wenn man z.b. Instanzvariablen mit primitive Datentypen von aussen direkt, also ohne Zugriff mittels Setters, ändert).
Eine technisch fundierte Begründung kann ich aber leider nicht liefern :)
Naja, das zu hinterfragen kann nicht schaden. Der Grund, warum man Getter– und Setter–Methoden eingeführt hat, ist Kapselung gewesen: die Freiheit, Attribute nach aussen hin anders zu präsentieren als sie innen vorliegen oder auch den Code ändern zu können, ohne dass man jeden Aufruf ändern muss.
Das ist aber bei einer dynamischen Sprache wie PHP kein Problem mehr, da man hier mit den magic getters und setters auch „normale“ Wertzuweisungen kapseln kann. Es gibt also keinen wirklichen Grund mehr, tatsächlich überall Getter und Setter zu verwenden. Das erhöht nur die Menge des Codes und damit auch die Komplexität.
LG,
CK
hi CK,
[..]Der Grund, warum man Getter– und Setter–Methoden eingeführt hat, ist Kapselung gewesen: die Freiheit, Attribute nach aussen hin anders zu präsentieren als sie innen vorliegen oder auch den Code ändern zu können, ohne dass man jeden Aufruf ändern muss.
Es gibt noch einen Grund, der ist mir gerade eben klar geworden, wo ich mein MVC-Framework so umgebaut habe, dass ein Wechsel der Template-Engine sozusagen auf 'Knopfdruck' möglich ist, d.h., es kann selbst zur Laufzeit das Template gewechselt werden, und zwar zwischen
Jetzt wäre es doof, wenn der Controller für unterschiedliche Templates auch unterschiedliche Daten bereitstellen würde (siehe Eingangsbeispiel .phtml, echo $this->dBase_Article->article()).
Ergo wird der Controller die Daten einheitlich in den STASH schreiben. So haben wir dann
im .phtml Template: Artikelname: <?php echo $this->stash('art','name')?>
im Twig-Template: Artikelname: {{art.name}}
und (nur) im Controller den magischen Zugriff auf die dBase_Article Class
$this->STASH['art'] = $this->dBase_Article->article4id(106);
Hahm mers endlich! Danke für Eure Aufmerksamkeit ;)
Horst Heizer
Hallo,
Mein Attribut 'dBase_Article' ist eine Instanz der Klasse 'dBase_Article' und wird über magic Method '__get(Access to inaccessible properties)' zur Laufzeit geschaffen, was dann den Methodenaufruf ermöglicht. Ist das (in der Templatedatei) OK, oder verstößt das gegen OOP-Grundsätze?
Also, ich verwende grundsätzlich ausschliesslich Getter und Setter um auf Instanz-Variablen zuzugreifen und nie Direkt-Zugriff.
Ok, das werde ich dann auch so handhaben, ist schon so vorbereitet.
Das liegt aber mehr an meiner eignen Arbeitsweise: Wenn ich für jede Instanz-Variable, die ich ausserhalb ändern/benutzen will einen Setter/Getter implementieren MUSS (und sei es auch nur, dass ich in Eclipse auf "Generate Getters/Setters" klicken muss :)), zwingt mich das dazu, mir genauer zu überlegen, welche Variablen nach aussen hin denn wirklich interessant /notwendig sind (und welche ich lieber "private" lasse, da andere Klassen daran eh nicht herumzufummeln haben).
Ja, so 'halb' nach draußen (obwohl der Namespace ja derselbe ist) ins Template. Magento zaubert über Magic-Methods die Getter/Setter selbst zusammen. In meinem bescheidenen kleinen Framework habe ich für die Verwendung in den Templates lediglich einen (einheitlichen) Getter:
echo $this->stash('url'); // wenn url ein String ist
echo $this->stash('addr','vname'); // wenn auf addr ein Array liegt
Dieser/mein Getter named 'stash' greift innerhalb der Response-Klasse auf das Attribut 'STASH', worin der Controller die Daten ablegt. Btw., Werte setzen, das macht bei mir nur der Controller, d.h., in den Templates gibt es nur den Getter und alles, was an Daten im Template gebraucht wird, stellt der Controller bereit.
Eine technisch fundierte Begründung kann ich aber leider nicht liefern :)
Es muss nicht immer alles technisch 'fundiert' begründet sein. Zweckmäßigkeit ist die Praxis ;)
In meinem MVC-FW kann als Alternative zu native PHP in Templates auch eine extra Template-Engine eingesetzt werden, da habe ich mich für Twig entschieden. Das Umschalten zur Twig-Engine erfolgt über ein Attribut, was zur Ausgabe des Puffers die Twig-Methode 'render' aufruft, die Übergabe der Daten fürs Template geht dann ebenfalls über das Attribut 'STASH'.
Viele Grüße,
Horst (immer noch auf der Suche nach einem Job im Rhein-Main-Gebiet)