Mam nadzieję, że temat który poruszę pasuje do tego miejsca.
Pierwsze opiszę dziedzinę zagadnienia:
Posiadam klasę, która zajmuje się przechowywaniem dowolnych danych (jej dokładna implementacja nie jest dziedziną problemu), ma dość dużą funkcjonalność (iterowanie, zachowywanie zbieżności z danymi zapisywanymi na stałe itp.). Dla naszych rozważań będę nazywał ją test. Klasa test ma 2 interesujące nas metody: get($sName) i set($sName, $mVal) służą one oczywiście do pobierania i zapisywania umieszczonych wewnątrz danych.
Szkic implementacji:
<?php class test { public function get($mName) { return $this->aTable[$mName]; } public function set($sName, $mVal) { $this->aTable[$sName] = $mVal; } } ?>
Jak wszyscy wiemy same dane to dopiero 30% sukcesu, trzeba na nich jakoś operować. Dlatego najczęściej piszemy klasę, która zawiera dane i metody operujące na nich. Szkoda jednak aby tak duża funkcjonalność klasy się zmarnowała, może ona przechowywać dla nas dowolne dane, zapisywać je w odpowiednie miejsce bez naszego kiwnięcia palcem! Daltego najlepiej byłoby w jakiś sposób rozszerzyć jej funkcjonalność. Nazwijmy nową klasę (operującą na danych z klasy test) test2:
<?php class test2 { public function __construct($Obj) { $this->Test = $Obj; } public function getA() { return $this->Test->get('a'); } } ?>
Operowanie w taki sposób na danych w klasie jest niewygodne, dlatego kolejnym krokiem mogłoby być dziedziczenie (musimy także pamiętać aby dane miały zasięg niepubliczny dlatego w klasie test akcesor public zamieniamy na protected):
<?php class test2 extends test { public function getA() { return $this->get('a'); } } ?>
Jednak w dalszym ciągu projektowanie takiego rozwinięcia do klasy test jest utrudnione. Najlepszym efektem byłoby bezpośrednie używanie zmiennych:
Kod
$this->a
Wydaje się teraz oczywiste użycie magicznych funkcji __get i __set:Niby wszystko działa... Jednak stała się katastrofa, metody __set i __get zawsze są publiczne. Dlatego możemy zrobić tak:
<?php class test { protected function __get($mName) { return $this->aTable[$mName]; } protected function __set($sName, $mVal) { $this->aTable[$sName] = $mVal; } } ?>
Co może prowadzić do katastrofy.
<?php $Obj = new test2(); $Obj->a = 5; ?>
Problem ten teoretycznie można rozwiązań używając funkcji debug_backtrace(). Oto teoretyczne rozwiązanie: http://phpfi.com/169155 . Takie rozwiązanie ma pewne plusy: możemy ustalać zasięg zmiennych, jednak z moich pomiarów wynika, że każde takie odwołanie jest o około 0.000025 sec wolniejsze niż bez sprawdzania miejsca uruchomienia.
Teraz podstawowe pytania: Czy taki czas jest dopuszczalny dla takiego ułatwienia? Może ktoś widzi inny sposób rozwiązania takiego przypadku?