Para ampliar la respuesta de Berry, que establecer el nivel de acceso en protected permite que __get y __set se usen con propiedades declaradas explícitamente (cuando se accede fuera de la clase, al menos) y la velocidad es considerablemente más lenta, citaré un comentario de otra pregunta sobre este tema y exponga su uso de todos modos:
Estoy de acuerdo en que __get es más lento para una función get personalizada (haciendo las mismas cosas), este es 0.0124455 el tiempo para __get () y este 0.0024445 es para get () personalizado después de 10000 bucles. - Melsi 23 de noviembre de 2012 a las 22:32 Mejores prácticas: Métodos PHP Magic __set y __get
Según las pruebas de Melsi, considerablemente más lento es aproximadamente 5 veces más lento. Eso es definitivamente considerablemente más lento, pero también tenga en cuenta que las pruebas muestran que aún puede acceder a una propiedad con este método 10,000 veces, contando el tiempo para la iteración del ciclo, en aproximadamente 1/100 de segundo. Es considerablemente más lento en comparación con los métodos get y set definidos, y eso es quedarse corto, pero en el gran esquema de las cosas, incluso 5 veces más lento nunca es realmente lento.
El tiempo de cálculo de la operación sigue siendo insignificante y no vale la pena considerarlo en el 99% de las aplicaciones del mundo real. El único momento en que realmente debería evitarse es cuando en realidad va a acceder a las propiedades más de 10,000 veces en una sola solicitud. Los sitios de alto tráfico están haciendo algo realmente mal si no pueden permitirse lanzar algunos servidores más para mantener sus aplicaciones en funcionamiento. Un anuncio de texto de una sola línea en el pie de página de un sitio de alto tráfico donde la tasa de acceso se convierte en un problema probablemente podría pagar por una granja de 1,000 servidores con esa línea de texto. El usuario final nunca va a tocar sus dedos preguntándose qué está tardando tanto en cargar la página porque el acceso a la propiedad de su aplicación tarda una millonésima de segundo.
Digo esto hablando como un desarrollador con experiencia en .NET, pero los métodos invisibles de obtención y configuración para el consumidor no son una invención de .NET. Simplemente no son propiedades sin ellos, y estos métodos mágicos son la gracia salvadora del desarrollador de PHP para incluso llamar "propiedades" a su versión de propiedades. Además, la extensión de Visual Studio para PHP admite intellisense con propiedades protegidas, con ese truco en mente, creo. Creo que con suficientes desarrolladores usando los métodos mágicos __get y __set de esta manera, los desarrolladores de PHP ajustarían el tiempo de ejecución para atender a la comunidad de desarrolladores.
Editar: En teoría, las propiedades protegidas parecían funcionar en la mayoría de las situaciones. En la práctica, resulta que muchas veces querrá utilizar sus captadores y definidores al acceder a propiedades dentro de la definición de clase y las clases extendidas. Una mejor solución es una clase base y una interfaz para cuando se extienden otras clases, por lo que puede copiar las pocas líneas de código de la clase base a la clase de implementación. Estoy haciendo un poco más con la clase base de mi proyecto, por lo que no tengo una interfaz para proporcionar en este momento, pero aquí está la definición de clase simplificada sin probar con la propiedad mágica obteniendo y configurando usando la reflexión para eliminar y mover las propiedades a una matriz protegida:
class Component {
protected $properties = array();
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;
}
}
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;
}
}
function __construct() {
$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;
}
}
Mis disculpas si hay algún error en el código.