Чтобы расширить ответ Берри, установка уровня доступа на protected позволяет использовать __get и __set с явно объявленными свойствами (по крайней мере, при доступе за пределами класса), а скорость значительно ниже, я процитирую комментарий из другого вопроса по этой теме и в любом случае приведите аргументы в пользу его использования:
Я согласен с тем, что __get медленнее настраивается на пользовательскую функцию get (делает то же самое), это 0,0124455 время для __get (), а 0,0024445 - для настраиваемого get () после 10000 циклов. - Мелси, 23 ноя., 2012, в 22:32 Лучшая практика: магические методы PHP __set и __get
Согласно тестам Мелси, значительно медленнее - примерно в 5 раз медленнее. Это определенно значительно медленнее, но также обратите внимание, что тесты показывают, что вы все еще можете получить доступ к свойству с помощью этого метода 10 000 раз, считая время для итерации цикла, примерно за 1/100 секунды. Это значительно медленнее по сравнению с определенными фактическими методами get и set, и это еще не все, но в целом даже в 5 раз медленнее никогда не бывает.
Время вычисления операции по-прежнему ничтожно и не стоит учитывать в 99% реальных приложений. Единственный раз, когда этого действительно следует избегать, - это когда вы фактически собираетесь обращаться к свойствам более 10 000 раз за один запрос. Сайты с высоким трафиком делают что-то действительно неправильно, если они не могут позволить себе добавить еще несколько серверов, чтобы их приложения работали. Однострочное текстовое объявление в нижнем колонтитуле сайта с высоким трафиком, где скорость доступа становится проблемой, вероятно, могло бы заплатить за ферму из 1000 серверов с этой строкой текста. Конечный пользователь никогда не будет постукивать пальцами, задаваясь вопросом, почему страница так долго загружается, потому что доступ к свойствам вашего приложения занимает миллионную долю секунды.
Я говорю это, говоря как разработчик, имеющий опыт работы с .NET, но невидимые для потребителя методы get и set не являются изобретением .NET. Они просто не являются свойствами без них, и эти волшебные методы - спасительная изящество разработчика PHP, которое даже может назвать свою версию свойств «свойствами». Кроме того, расширение Visual Studio для PHP поддерживает intellisense с защищенными свойствами, я думаю, имея в виду этот трюк. Я бы подумал, что с достаточным количеством разработчиков, использующих магические методы __get и __set таким образом, разработчики PHP настроят время выполнения, чтобы удовлетворить потребности сообщества разработчиков.
Изменить: Теоретически защищенные свойства казалось, что они будут работать в большинстве ситуаций. На практике оказывается, что во многих случаях вы захотите использовать свои геттеры и сеттеры при доступе к свойствам в определении класса и расширенных классах. Лучшее решение - это базовый класс и интерфейс для расширения других классов, поэтому вы можете просто скопировать несколько строк кода из базового класса в реализующий класс. Я делаю немного больше с базовым классом моего проекта, поэтому у меня нет интерфейса, который я мог бы предоставить прямо сейчас, но вот непроверенное урезанное определение класса с получением и настройкой магического свойства с использованием отражения для удаления и перемещения свойств в защищенный массив:
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;
}
}
Приношу свои извинения, если в коде есть ошибки.