Para expandir a resposta de Berry, que definir o nível de acesso como protegido permite que __get e __set sejam usados com propriedades declaradas explicitamente (quando acessados fora da classe, pelo menos) e a velocidade sendo consideravelmente mais lenta, citarei um comentário de outra pergunta sobre este tópico e tente usá-lo de qualquer maneira:
Eu concordo que __get é mais lento para uma função get customizada (fazendo as mesmas coisas), isto é 0,0124455 o tempo para __get () e 0,0024445 é para get () customizado após 10.000 loops. - Melsi 23 de novembro de 12 às 22:32 Prática recomendada: métodos mágicos de PHP __set e __get
De acordo com os testes de Melsi, consideravelmente mais lento é cerca de 5 vezes mais lento. Isso é definitivamente consideravelmente mais lento, mas observe também que os testes mostram que você ainda pode acessar uma propriedade com esse método 10.000 vezes, contando o tempo para a iteração do loop, em cerca de 1/100 de segundo. É consideravelmente mais lento em comparação com os métodos get e set reais definidos, e isso é um eufemismo, mas no grande esquema das coisas, mesmo 5 vezes mais lento nunca é realmente lento.
O tempo de computação da operação ainda é insignificante e não vale a pena ser considerado em 99% dos aplicativos do mundo real. A única vez que isso realmente deve ser evitado é quando você realmente vai acessar as propriedades mais de 10.000 vezes em uma única solicitação. Os sites de alto tráfego estão fazendo algo realmente errado se não podem arcar com o aumento de alguns servidores para manter seus aplicativos em execução. Um anúncio de texto de uma única linha no rodapé de um site de alto tráfego, onde a taxa de acesso se torna um problema, provavelmente pagaria por um conjunto de 1.000 servidores com essa linha de texto. O usuário final nunca vai ficar batendo os dedos se perguntando por que a página está demorando tanto para carregar porque o acesso à propriedade do seu aplicativo leva um milionésimo de segundo.
Digo isso falando como um desenvolvedor vindo de .NET, mas os métodos invisíveis get e set para o consumidor não são invenção do .NET. Eles simplesmente não são propriedades sem eles, e esses métodos mágicos são a graça salvadora do desenvolvedor do PHP por até mesmo chamar sua versão de propriedades de "propriedades". Além disso, a extensão do Visual Studio para PHP oferece suporte a intellisense com propriedades protegidas, com esse truque em mente, eu acho. Eu acho que com desenvolvedores suficientes usando os métodos mágicos __get e __set dessa forma, os desenvolvedores de PHP ajustariam o tempo de execução para atender à comunidade de desenvolvedores.
Edit: Em teoria, as propriedades protegidas pareciam funcionar na maioria das situações. Na prática, acontece que muitas vezes você vai querer usar seus getters e setters ao acessar propriedades dentro da definição de classe e classes estendidas. Uma solução melhor é uma classe base e interface para quando estender outras classes, portanto, você pode apenas copiar algumas linhas de código da classe base para a classe de implementação. Estou fazendo um pouco mais com a classe base do meu projeto, então não tenho uma interface para fornecer agora, mas aqui está a definição de classe reduzida não testada com propriedade mágica obtendo e configurando usando reflexão para remover e mover as propriedades para uma 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;
}
}
Minhas desculpas se houver algum bug no código.