Jak można było zauważyć w poprzednim wpisie funkcja get_object_vars() realizuje de facto zadanie pobrania wartości i nazw pól klas. Jej wadą jest jednak niemożność dojścia do metod prywatnych przodków naszej klasy i właśnie w celu dodania tej funkcjonalności niezbędne okażą się klasy Reflection.
Na początek przypomnijmy jednak sobie naszą hierarchię klas...
class First { private $firstPrivate; protected $firstProtected; public $firstPublic="DEFAULT"; } class Second extends First { private $secondPrivate; protected $secondProtected; public $secondPublic; } class Third extends Second { private $thirdPrivate; protected $thirdProtected; public $thirdPublic; }
Aby dobrać się do metod prywatnych potrzebujemy o wiele bardziej rozbudowanego kodu niż ten umieszczony w poprzednim wpisie, oraz rekurencji koniecznej do przejścia po grafu dziedziczenia klas.
Takim chyba najprostszym przykładem pobrania wartości wszystkich parametrów jest funkcja:
function getAllFields($object) { $globalFields = array(); $reflectionClass = new ReflectionClass($object); do { $reflections = $reflectionClass->getProperties(); foreach($reflections as $reflectionProperty) { $reflectionProperty->setAccessible(true); $globalFields[$reflectionProperty->name] = $reflectionProperty->getValue($object); } $reflectionClass = $reflectionClass->getParentClass(); } while($reflectionClass); return $globalFields; }dająca taki oto rezultat
Array ( [thirdPrivate] => [thirdProtected] => [thirdPublic] => NEW [secondProtected] => [secondPublic] => [firstProtected] => [firstPublic] => DEFAULT [secondPrivate] => [firstPrivate] => NEW PRIVATE )Funkcję ta jednak ma główną wadę w postaci nadpisywania zmiennych klas bliższych badanemu obiektowi przez zmienne jego przodków. Na szczęście można tą funkcję dowolnie rozwijać i sprawić by generowała wszelkie informacje dotyczące badanej klasy:
function getAllFieldsStrict($object) { $globalFields = array(); $reflectionClass = new ReflectionClass($object); do { $reflections = $reflectionClass->getProperties(); foreach($reflections as $reflectionProperty) { if($reflectionProperty->getDeclaringClass()->name == $reflectionProperty->name) { switch(true) { case $reflectionProperty->isPrivate(): $globalFields[$reflectionProperty->name][$reflectionProperty->name]['access'] = 'private'; break; case $reflectionProperty->isProtected(): $globalFields[$reflectionProperty->name][$reflectionProperty->name]['access'] = 'protected'; break; case $reflectionProperty->isPublic(): $globalFields[$reflectionProperty->name][$reflectionProperty->name]['access'] = 'public'; break; } $reflectionProperty->setAccessible(true); $globalFields[$reflectionProperty->name][$reflectionProperty->name]['value'] = $reflectionProperty->getValue($object); $globalFields[$reflectionProperty->name][$reflectionProperty->name]['static'] = $reflectionProperty->isStatic(); } } $reflectionClass = $reflectionClass->getParentClass(); } while($reflectionClass); return $globalFields; }czego rezultatem jest
Array ( [Third] => Array ( [thirdPrivate] => Array ( [value] => [static] => [access] => private ) [thirdProtected] => Array ( [value] => [static] => [access] => protected ) [thirdPublic] => Array ( [value] => NEW [static] => [access] => public ) ) [Second] => Array ( [secondPrivate] => Array ( [value] => [static] => [access] => private ) [secondProtected] => Array ( [value] => [static] => [access] => protected ) [secondPublic] => Array ( [value] => [static] => [access] => public ) ) [First] => Array ( [firstPrivate] => Array ( [value] => NEW PRIVATE [static] => [access] => private ) [firstProtected] => Array ( [value] => [static] => [access] => protected ) [firstPublic] => Array ( [value] => DEFAULT [static] => [access] => public ) ) )
Wydajność
get_object_vars: 0.28459501266479 getAllFields: 4.3010709285736 getAllFieldsStrict: 4.3191359043121Podczas testu wykonano każde z zapytań 100000 razy i jak widać wygenerowanie rozbudowanej struktury klas zajmuje praktycznie tyle samo czasu co stworzenie prostszej. Mimo wszystko jednak generowanie trwa ok. 15 razy dłużej w porównaniu do wyciągnięcia informacji za pomocą get_object_vars(), dlatego też jeśli potrzebujemy dostać się do zmiennych klas i mamy możliwość deklarowania pól jako protected a nie private - to zdecydowanie lepiej tak zrobić i używać get_object_vars().
Przykładowy kod do testowania można pobrać z mojego chomika (link).
Brak komentarzy:
Prześlij komentarz