Ich bin kein PHP-Entwickler, daher frage ich mich, ob es in PHP beliebter ist, explizite Getter / Setter in einem reinen OOP-Stil mit privaten Feldern zu verwenden (wie ich es mag):
class MyClass {
private $firstField;
private $secondField;
public function getFirstField() {
return $this->firstField;
}
public function setFirstField($x) {
$this->firstField = $x;
}
public function getSecondField() {
return $this->secondField;
}
public function setSecondField($x) {
$this->secondField = $x;
}
}
oder nur öffentliche Felder:
class MyClass {
public $firstField;
public $secondField;
}
Vielen Dank
php
oop
coding-style
Kennzeichen
quelle
quelle
Antworten:
Sie können PHP Magic Methoden
__get
und verwenden__set
.quelle
__get
und__set
. Es gibt zwei Unterstriche, keinen. Hier ist der direkte Link zum rechten Teil der Seite: php.net/manual/en/… (+1 für eine korrekte Antwort)public
Immobilien, wenn es keine Validierung / Hygiene gibt?Warum Getter und Setter verwenden?
quelle
Google hat bereits einen Leitfaden zur Optimierung von PHP veröffentlicht. Die Schlussfolgerung lautete:
Kein Getter und Setter PHP optimieren
Und nein, Sie dürfen keine magischen Methoden anwenden . Für PHP sind Magic Method böse. Warum?
PHP ist nicht Java, C ++ oder C #. PHP ist anders und spielt mit verschiedenen Rollen.
quelle
$dog->name = 'fido'
ist besser als$dog->setName('fido')
. Wenn eine Eigenschaft tatsächlich mutiert wird (Beispiel:$dog->increaseAge(1)
Ich kann die Methode ausbauen, die die erforderliche Validierung durchführt und diese Eigenschaft mutiert. Aber nicht alle Aktionen erfordern wirklich eine Mutation in diesem Sinne.Kapselung ist in jeder OO-Sprache wichtig, Popularität hat nichts damit zu tun. In dynamisch typisierten Sprachen wie PHP ist dies besonders nützlich, da es kaum Möglichkeiten gibt, sicherzustellen, dass eine Eigenschaft von einem bestimmten Typ ist, ohne Setter zu verwenden.
In PHP funktioniert dies:
In Java ist dies nicht der Fall:
Die Verwendung magischer Methoden (
__get
und__set
) funktioniert ebenfalls, jedoch nur, wenn auf eine Eigenschaft zugegriffen wird, die eine geringere Sichtbarkeit als der aktuelle Bereich aufweist. Es kann leicht Kopfschmerzen beim Debuggen verursachen, wenn es nicht richtig verwendet wird.quelle
$bar
alsint
im ersten Beispiel deklarierenWenn Sie die Funktion __call bevorzugen, können Sie diese Methode verwenden. Es funktioniert mit
$this->property()
$this->property($value)
$this->getProperty()
$this->setProperty($value)
kalsdas
quelle
property_exists(get_class($this), $name)
und die Rekursion ist langsam. Es gibt eine Möglichkeit, dies durch Cacheing zu verringern, aber es wird immer noch langsamer sein, als die Getter und Setter von Hand zu erstellen. Ich habe das nur als Alternative geschrieben. Ich empfehle eigentlich nicht, "Magic Methods" zu verwenden. Die zusätzliche Zeit zum Erstellen der Getter und Setter ist normalerweise unbedeutend.Zusätzlich zu den bereits großartigen und angesehenen Antworten hier möchte ich PHP ohne Setter / Getter erweitern.
PHP hat keine Getter- und Setter-Syntax . Es bietet untergeordnete oder magische Methoden, um das "Verknüpfen" und Überschreiben des Eigenschaftssuchprozesses zu ermöglichen, wie von Dave hervorgehoben .
Mit Magic können wir faulen Programmierer mit weniger Code mehr erreichen, wenn wir aktiv an einem Projekt beteiligt sind und es genau kennen, aber normalerweise auf Kosten der Lesbarkeit.
Leistung Jede unnötige Funktion, die sich aus dem Erzwingen einer Getter / Setter-ähnlichen Code-Architektur in PHP ergibt, beinhaltet beim Aufruf einen eigenen Speicher-Stack-Frame und verschwendet CPU-Zyklen.
Lesbarkeit: Die Codebasis führt zu aufgeblähten Codezeilen, was sich auf die Code-Navigation auswirkt, da mehr LOC mehr Scrollen bedeutet.
Präferenz: Persönlich nehme ich als Faustregel das Versagen der statischen Code-Analyse als Zeichen, um zu vermeiden, den magischen Weg zu gehen, solange mir zu diesem Zeitpunkt offensichtliche langfristige Vorteile entgehen.
Irrtümer:
Ein häufiges Argument ist die Lesbarkeit. Zum Beispiel
$someobject->width
ist das leichter zu lesen als$someobject->width()
. Im Gegensatz zu der Instanz eines Planetencircumference
oderwidth
, wie angenommen werden kannstatic
, nimmt die Instanz eines Objekts, wie beispielsweise$someobject
eine Breitenfunktion, wahrscheinlich eine Messung der Instanzbreite des Objekts vor.Daher erhöht sich die Lesbarkeit hauptsächlich aufgrund durchsetzungsfähiger Benennungsschemata und nicht durch Ausblenden der Funktion, die einen bestimmten Eigenschaftswert ausgibt.
__get / __set verwendet:
Vorvalidierung und Hygiene von Immobilienwerten
Saiten zB
In diesem Fall
generatelatex
würde ein Namensschema von Aktionsname + Methodenname eingehaltenbesondere, offensichtliche Fälle
Hinweis: PHP hat sich dafür entschieden, die Getter / Setter-Syntax nicht zu implementieren. Ich behaupte nicht, dass Getter / Setter im Allgemeinen schlecht sind.
quelle
Bereit!
quelle
Nun, PHP zaubern Methoden
__get
,__set
,__isset
&__unset
, das ist immer ein Anfang. Leider sind OO-Eigenschaften mehr als magische Methoden. Das Hauptproblem bei der Implementierung von PHP besteht darin, dass für alle unzugänglichen Eigenschaften magische Methoden aufgerufen werden. Das heißt, Sie müssen sich in den magischen Methoden wiederholen (z. B. durch Aufrufen von property_exists ()), um festzustellen, ob der Name tatsächlich eine Eigenschaft Ihres Objekts ist. Und Sie können dieses allgemeine Problem nicht wirklich mit einer Basisklasse lösen, es sei denn, alle Ihre Klassen erben von dh. ClassWithProperties, da PHP keine Mehrfachvererbung aufweist.Im Gegensatz dazu erhalten Sie neue Python- Stilklassen
property()
, mit denen Sie alle Ihre Eigenschaften explizit definieren können. C # hat eine spezielle Syntax.http://en.wikipedia.org/wiki/Property_(programming)
quelle
Ich habe ein Experiment mit der magischen Methode __call gemacht. Ich bin mir nicht sicher, ob ich es posten soll (wegen all der Warnungen "KEINE MAGISCHEN METHODEN VERWENDEN" in den anderen Antworten und Kommentaren), aber ich werde es hier lassen ... nur für den Fall, dass jemand es nützlich findet.
Fügen Sie diese Methode einfach oben in Ihre Klasse ein. Jetzt können Sie Folgendes eingeben:
Auf diese Weise können Sie alles in Ihrer Klasse abrufen / festlegen, sofern es vorhanden ist. Wenn Sie es also nur für einige bestimmte Elemente benötigen, können Sie eine "Whitelist" als Filter verwenden.
Beispiel:
Jetzt können Sie nur noch "foo" und "fee" erhalten / einstellen.
Sie können diese "Whitelist" auch verwenden, um benutzerdefinierte Namen für den Zugriff auf Ihre Variablen zuzuweisen.
Beispielsweise,
Mit dieser Liste können Sie nun Folgendes eingeben:
.
.
.
Das ist alles.
Doc: __call () wird ausgelöst, wenn unzugängliche Methoden in einem Objektkontext aufgerufen werden .
quelle
Nachdem ich die anderen Ratschläge gelesen habe, neige ich dazu zu sagen:
Als GENERISCHE Regel definieren Sie nicht immer Setter für ALLE Eigenschaften, insbesondere für "interne" (Semaphoren, interne Flags ...). Schreibgeschützte Eigenschaften haben offensichtlich keine Setter, daher haben einige Eigenschaften nur Getter. Hier kommt __get (), um den Code zu verkleinern:
Ja! Wir könnten auch eine private Methode schreiben, um dies zu tun, aber andererseits werden VIELE Methoden deklariert (++ Speicher), die am Ende eine andere, immer dieselbe Methode aufrufen. Warum nicht einfach eine EINZELNE Methode schreiben , um sie alle zu regieren ...? [ja! Wortspiel absolut beabsichtigt! :)]
Magic Setter können auch NUR auf bestimmte Eigenschaften reagieren, sodass alle Datumstyp-Eigenschaften nur in einer Methode auf ungültige Werte überprüft werden können. Wenn Datumstyp-Eigenschaften in einem Array aufgelistet wurden, können deren Setter einfach definiert werden. Nur ein Beispiel natürlich. Es gibt viel zu viele Situationen.
Über Lesbarkeit ... Nun ... Das ist eine weitere Debatte: Ich bin nicht gerne an die Verwendung einer IDE gebunden (tatsächlich verwende ich sie nicht, sie neigen dazu, mir zu sagen (und mich zu zwingen ), wie es geht schreibe ... und ich habe meine Vorlieben für das Codieren von "Schönheit"). Ich neige dazu, konsequent zu benennen, daher reicht es mir aus, ctags und ein paar andere Hilfsmittel zu verwenden ... Wie auch immer: Sobald all diese magischen Setter und Getter fertig sind, schreibe ich die anderen Setter, die zu spezifisch oder "speziell" sind in einer __set () -Methode verallgemeinert werden. Und das deckt alles ab, was ich zum Abrufen und Festlegen von Eigenschaften benötige. Natürlich: Es gibt nicht immer eine gemeinsame Basis, oder es gibt so einige Eigenschaften, die die Mühe, eine magische Methode zu codieren, nicht wert sind, und dann gibt es immer noch das alte gute traditionelle Setter / Getter-Paar.
Programmiersprachen sind genau das: menschliche künstliche Sprachen. Jeder von ihnen hat seine eigene Intonation oder seinen eigenen Akzent, seine eigene Syntax und seinen eigenen Geschmack. Ich werde also nicht so tun, als würde ich einen Ruby- oder Python-Code mit demselben "Akzent" wie Java oder C # schreiben, noch würde ich ein JavaScript oder PHP schreiben, das ähnelt Perl oder SQL ... Verwenden Sie sie so, wie sie verwendet werden sollen.
quelle
Im Allgemeinen ist der erste Weg insgesamt beliebter, da Personen mit Programmierkenntnissen problemlos auf PHP umsteigen und ihre Arbeit objektorientiert erledigen können. Der erste Weg ist universeller. Mein Rat wäre, sich an das zu halten, was in vielen Sprachen bewährt ist. Wenn Sie dann eine andere Sprache verwenden, sind Sie bereit, etwas zu erreichen ( anstatt Zeit damit zu verbringen, das Rad neu zu erfinden ).
quelle
Es gibt viele Möglichkeiten, Quellcode in einer Netbeans-Konvention zu erstellen. Das ist nett. Es macht das Denken so einfacher === FALSE. Verwenden Sie einfach die Tradition, insbesondere wenn Sie nicht sicher sind, welche der Eigenschaften gekapselt werden soll und welche nicht. Ich weiß, es ist ein Boi ... Pla ... Code, aber für Debugging-Arbeiten und viele andere hält es für den besseren, klaren Weg. Verbringen Sie nicht zu viel Zeit mit Tausenden von Künsten, um einfache Getter und Setter herzustellen. Sie können nicht zu viele Entwurfsmuster wie die Demeter-Regel usw. implementieren, wenn Sie Magie verwenden. In bestimmten Situationen können Sie magic_calls oder kleine, schnelle und klare Lösungen verwenden. Natürlich könnten Sie auch auf diese Weise Lösungen für Designmuster finden, aber warum sollten Sie das Leben schwieriger machen?
quelle
Validieren + Formatieren / Ableiten von Werten
Mit Setzern können Sie Daten validieren und mit Gettern können Sie Daten formatieren oder ableiten. Mit Objekten können Sie Daten und ihren Validierungs- und Formatierungscode in einem übersichtlichen Paket zusammenfassen, das DRY fördert.
Betrachten Sie beispielsweise die folgende einfache Klasse, die ein Geburtsdatum enthält.
Sie möchten überprüfen, ob der festgelegte Wert lautet
Und Sie möchten diese Validierung nicht für Ihre gesamte Anwendung (oder für mehrere Anwendungen) durchführen. Stattdessen ist es einfacher, die Mitgliedsvariable geschützt oder privat zu machen (um den Setter zum einzigen Zugriffspunkt zu machen) und im Setter zu validieren, da Sie dann wissen, dass das Objekt ein gültiges Geburtsdatum enthält, unabhängig davon, welcher Teil des Anwendung, aus der das Objekt stammt, und wenn Sie weitere Validierungen hinzufügen möchten, können Sie es an einer einzigen Stelle hinzufügen.
Möglicherweise möchten Sie mehrere Formatierer hinzufügen, die mit derselben Mitgliedsvariablen arbeiten, z. B.
getAge()
und je nach GebietsschemagetDaysUntilBirthday()
ein konfigurierbares Format erzwingengetBirthDate()
. Daher bevorzuge ich den konsequenten Zugriff auf Werte über Getter im Gegensatz zum Mischen$date->getAge()
mit$date->birth_date
.Getter und Setter sind auch nützlich, wenn Sie Objekte erweitern. Angenommen, Ihre Bewerbung muss an einigen Orten Geburtsdaten von mehr als 150 Jahren zulassen, an anderen jedoch nicht. Eine Möglichkeit, das Problem zu lösen, ohne Code zu wiederholen, besteht darin, das
BirthDate
Objekt zu erweitern und die zusätzliche Validierung in den Setter zu stellen.quelle
setHired
undsetHireDate
. Es ist nicht gültig, jemanden ein Einstellungsdatum festlegen zu lassen, ohne auch den Mitarbeiter als eingestellt festzulegen. Aber Sie haben dies auf keinen Fall durchgesetzt. Wenn Sie es in einem dieser Setter erzwingen, erzwingen Sie die Reihenfolge der "Einstellung", und dies erfordert mehr Code-Lesen von einem Entwickler, um dies zu wissen. Wenn Sie dann eine Methode wie diese$employee->promote($newPosition);
ausführen, müssen Sie ein Flag überprüfen, um festzustellen, ob die Validierung durchgeführt wurde, oder annehmen, dass sie nicht durchgeführt wurde, und sie erneut ausführen (redundant).$employee->updateWorkStatus($hired, $hireDate);
oder wenn fortgeschrittener$employee->adminUpdate(\Employee\AdminUpdateDTO $dto);
. Jetzt können Sie im gewünschten Kontext validieren und entscheiden, ob überhaupt eine zusätzliche Validierung erforderlich ist.In diesem Beitrag geht es nicht speziell um
__get
und__set
sondern um__call
die gleiche Idee, außer für den Methodenaufruf. In der Regel halte ich mich von jeglichen magischen Methoden fern, die aus den in den Kommentaren und Beiträgen genannten Gründen eine Überladung ermöglichen. JEDOCH bin ich kürzlich auf eine Drittanbieter-API gestoßen , die ich verwende und die beispielsweise einen SERVICE und einen SUB-SERVICE verwendet ::Der wichtige Teil davon ist, dass diese API bis auf die Unteraktion in diesem Fall alles gleich hat
doActionOne
. Die Idee ist, dass der Entwickler (ich und andere, die diese Klasse verwenden) den Subdienst beim Namen nennen könnte, im Gegensatz zu etwas wie:Ich könnte stattdessen tun:
Das Hardcodieren wäre nur eine Menge Duplizierung (dieses Beispiel ähnelt dem Code sehr stark):
Aber mit der magischen Methode von kann
__call()
ich mit dynamischen Methoden auf alle Dienste zugreifen:Der Vorteil dieser dynamischen Aufforderung zur Rückgabe von Daten besteht darin, dass ich, wenn der Anbieter einen weiteren Unterdienst hinzufügt, der Klasse keine weitere Methode hinzufügen oder eine erweiterte Klasse usw. erstellen muss. Ich bin mir nicht sicher, ob dies nützlich ist jemand, aber ich dachte , ich würde ein Beispiel zeigen , wo
__set
,__get
,__call
etc. eine Option zur Prüfung sein kann , da die primäre Funktion die Rückgabe von Daten ist.BEARBEITEN:
Zufälligerweise habe ich dies einige Tage nach der Veröffentlichung gesehen, was genau mein Szenario beschreibt. Es ist nicht die API, auf die ich mich bezog, aber die Anwendung der Methoden ist identisch:
Benutze ich API richtig?
quelle
Update: Verwenden Sie diese Antwort nicht, da dies sehr dummer Code ist, den ich beim Lernen gefunden habe. Verwenden Sie einfach Getter und Setter, es ist viel besser.
Normalerweise verwende ich diesen Variablennamen als Funktionsnamen und füge dieser Funktion einen optionalen Parameter hinzu. Wenn dieser optionale Parameter vom Aufrufer ausgefüllt wird, setze ich ihn auf die Eigenschaft und gebe $ this object (Verkettung) zurück, und wenn dieser optionale Parameter nicht von angegeben wird Anrufer, ich gebe nur die Eigenschaft an den Anrufer zurück.
Mein Beispiel:
quelle