Щоб розширити відповідь Беррі, установка рівня доступу на захищений дозволяє використовувати __get і __set із явно оголошеними властивостями (принаймні при доступі поза класом), а швидкість значно менша, я цитую коментар з іншого питання на цю тему та все одно обґрунтуйте її використання:
Я погоджуюсь, що __get повільніше користується користувацькою функцією отримання (виконуючи ті самі дії), це 0.0124455 час для __get (), а це 0.0024445 для користувацького get () після 10000 циклів. - Мельсі, 23 листопада '12 о 22:32 Найкраща практика: PHP Magic Methods __set та __get
Згідно з тестами Мельсі, значно повільніше - приблизно в 5 разів повільніше. Це, безумовно, значно повільніше, але також зауважте, що тести показують, що ви все одно можете отримати доступ до властивості за допомогою цього методу 10000 разів, вважаючи час для ітерації циклу, приблизно в 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;
}
}
Прошу вибачення, якщо в коді є помилки.