Um Berrys Antwort zu erweitern: Wenn Sie die Zugriffsebene auf "Geschützt" setzen, können __get und __set mit explizit deklarierten Eigenschaften verwendet werden (zumindest beim Zugriff außerhalb der Klasse). Da die Geschwindigkeit erheblich langsamer ist, zitiere ich einen Kommentar aus einer anderen Frage zu diesem Thema und begründen Sie es trotzdem:
Ich bin damit einverstanden, dass __get für eine benutzerdefinierte Get-Funktion langsamer ist (die gleichen Aktionen ausführt). Dies ist 0,0124455 für __get () und 0,0024445 für benutzerdefinierte get () nach 10000 Schleifen. - Melsi 23. November 12 um 22:32 Best Practice: PHP Magic Methoden __set und __get
Nach Melsis Tests ist erheblich langsamer etwa fünfmal langsamer. Das ist definitiv erheblich langsamer, aber beachten Sie auch, dass die Tests zeigen, dass Sie mit dieser Methode immer noch 10.000 Mal auf eine Eigenschaft zugreifen können, wobei die Zeit für die Schleifeniteration in ungefähr 1/100 Sekunde gezählt wird. Es ist im Vergleich zu den tatsächlich definierten Get- und Set-Methoden erheblich langsamer, und das ist eine Untertreibung, aber im großen Schema der Dinge ist sogar fünfmal langsamer nie wirklich langsam.
Die Rechenzeit des Vorgangs ist immer noch vernachlässigbar und in 99% der realen Anwendungen nicht zu berücksichtigen. Das einzige Mal, dass es wirklich vermieden werden sollte, ist, wenn Sie in einer einzigen Anfrage mehr als 10.000 Mal auf die Eigenschaften zugreifen. Websites mit hohem Datenverkehr machen etwas wirklich Falsches, wenn sie es sich nicht leisten können, ein paar weitere Server hochzuwerfen, um ihre Anwendungen am Laufen zu halten. Eine einzeilige Textanzeige in der Fußzeile einer stark frequentierten Site, bei der die Zugriffsrate zum Problem wird, könnte wahrscheinlich für eine Farm mit 1.000 Servern mit dieser Textzeile bezahlt werden. Der Endbenutzer wird niemals mit den Fingern tippen und sich fragen, was das Laden der Seite so lange dauert, da der Zugriff auf die Eigenschaften Ihrer Anwendung eine Millionstel Sekunde dauert.
Ich sage dies als Entwickler mit einem Hintergrund in .NET, aber unsichtbare Methoden zum Abrufen und Festlegen für den Verbraucher sind keine Erfindung von .NET. Sie sind einfach keine Eigenschaften ohne sie, und diese magischen Methoden sind die Rettung des PHP-Entwicklers, wenn es darum geht, ihre Version von Eigenschaften überhaupt als "Eigenschaften" zu bezeichnen. Außerdem unterstützt die Visual Studio-Erweiterung für PHP Intellisense mit geschützten Eigenschaften, mit diesem Trick, denke ich. Ich würde denken, wenn genügend Entwickler die magischen Methoden __get und __set auf diese Weise verwenden, würden die PHP-Entwickler die Ausführungszeit optimieren, um der Entwicklergemeinschaft gerecht zu werden.
Bearbeiten: Theoretisch schienen geschützte Eigenschaften in den meisten Situationen zu funktionieren. In der Praxis stellt sich heraus, dass Sie häufig Ihre Getter und Setter verwenden möchten, wenn Sie auf Eigenschaften innerhalb der Klassendefinition und der erweiterten Klassen zugreifen. Eine bessere Lösung ist eine Basisklasse und eine Schnittstelle für die Erweiterung anderer Klassen, sodass Sie nur die wenigen Codezeilen aus der Basisklasse in die implementierende Klasse kopieren können. Ich mache ein bisschen mehr mit der Basisklasse meines Projekts, daher muss ich momentan keine Schnittstelle bereitstellen, aber hier ist die ungetestete, reduzierte Klassendefinition mit dem Abrufen und Festlegen magischer Eigenschaften mithilfe von Reflektion zum Entfernen und Verschieben der Eigenschaften ein geschütztes Array:
/** Base class with magic property __get() and __set() support for defined properties. */
class Component {
/** Gets the properties of the class stored after removing the original
* definitions to trigger magic __get() and __set() methods when accessed. */
protected $properties = array();
/** Provides property get support. Add a case for the property name to
* expand (no break;) or replace (break;) the default get method. When
* overriding, call parent::__get($name) first and return if not null,
* then be sure to check that the property is in the overriding class
* before doing anything, and to implement the default get routine. */
public function __get($name) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
return $this->properties[$name]->value;
}
}
/** Provides property set support. Add a case for the property name to
* expand (no break;) or replace (break;) the default set method. When
* overriding, call parent::__set($name, $value) first, then be sure to
* check that the property is in the overriding class before doing anything,
* and to implement the default set routine. */
public function __set($name, $value) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
$this->properties[$name]->value = $value;
}
}
/** Constructor for the Component. Call first when overriding. */
function __construct() {
// Removing and moving properties to $properties property for magic
// __get() and __set() support.
$reflected_class = new ReflectionClass($this);
$properties = array();
foreach ($reflected_class->getProperties() as $property) {
if ($property->isStatic()) { continue; }
$properties[$property->name] = (object)array(
'name' => $property->name, 'value' => $property->value
, 'access' => $property->getModifier(), 'class' => get_class($this));
unset($this->{$property->name}); }
$this->properties = $properties;
}
}
Ich entschuldige mich, wenn der Code Fehler enthält.