Aby rozwinąć odpowiedź Berry'ego, że ustawienie poziomu dostępu na protected pozwala __get i __set na użycie z jawnie zadeklarowanymi właściwościami (przynajmniej w przypadku dostępu poza klasą), a prędkość jest znacznie wolniejsza, zacytuję komentarz z innego pytania na ten temat i tak czy owak uzasadnij jego użycie:
Zgadzam się, że __get działa wolniej niż niestandardowa funkcja get (robi to samo), jest to 0,0124455 czas dla __get () i 0,0024445 dla niestandardowej funkcji get () po 10000 pętli. - Melsi Lis 23 '12 o 22:32 Najlepsza praktyka: Magiczne metody PHP __set i __get
Według testów Melsi, znacznie wolniejszy jest około 5 razy wolniejszy. Jest to zdecydowanie wolniejsze, ale należy również zauważyć, że testy pokazują, że nadal można uzyskać dostęp do właściwości za pomocą tej metody 10000 razy, licząc czas iteracji pętli, w przybliżeniu w 1/100 sekundy. Jest znacznie wolniejszy w porównaniu z rzeczywistymi zdefiniowanymi metodami pobierania i ustawiania, i to mało powiedziane, ale w ogólnym rozrachunku nawet 5 razy wolniej nigdy nie jest tak naprawdę powolne.
Czas obliczeniowy operacji jest nadal znikomy i nie warty rozważenia w 99% rzeczywistych aplikacji. Jedynym przypadkiem, którego naprawdę należy unikać, jest fakt, że zamierzasz uzyskać dostęp do właściwości ponad 10000 razy w jednym żądaniu. Witryny o dużym ruchu robią coś naprawdę złego, jeśli nie stać ich na wyrzucenie kilku serwerów więcej, aby ich aplikacje działały. Jednowierszowa reklama tekstowa w stopce witryny o dużym natężeniu ruchu, w której szybkość dostępu staje się problemem, mogłaby prawdopodobnie zapłacić za farmę 1000 serwerów z tym wierszem tekstu. Użytkownik końcowy nigdy nie będzie dotykał palcami, zastanawiając się, co tak długo trwa ładowanie strony, ponieważ dostęp do właściwości aplikacji zajmuje milionową część sekundy.
Mówię, że jako programista wywodzący się z doświadczenia w .NET, ale niewidoczne metody pobierania i ustawiania dla konsumenta nie są wymysłem .NET. Po prostu nie są one właściwościami bez nich, a te magiczne metody są dla programistów PHP zachowaniem, które pozwala nawet nazywanie ich wersji właściwości „właściwościami”. Ponadto rozszerzenie Visual Studio dla PHP obsługuje technologię Intellisense z chronionymi właściwościami, myślę, że mając na uwadze tę sztuczkę. Myślę, że przy wystarczającej liczbie programistów używających w ten sposób magicznych metod __get i __set programiści PHP dostroiliby czas wykonywania, aby zaspokoić potrzeby społeczności programistów.
Edycja: Teoretycznie chronione właściwości wydawały się działać w większości sytuacji. W praktyce okazuje się, że wiele razy będziesz chciał użyć swoich metod pobierających i ustawiających podczas uzyskiwania dostępu do właściwości w ramach definicji klasy i klas rozszerzonych. Lepszym rozwiązaniem jest klasa bazowa i interfejs do rozszerzania innych klas, więc możesz po prostu skopiować kilka wierszy kodu z klasy bazowej do klasy implementującej. Robię trochę więcej z klasą bazową mojego projektu, więc nie mam teraz interfejsu do udostępnienia, ale oto niesprawdzona, uproszczona definicja klasy z magiczną właściwością, która pobiera i ustawia za pomocą odbicia w celu usunięcia i przeniesienia właściwości do chroniona tablica:
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;
}
}
Przepraszam, jeśli w kodzie są jakieś błędy.