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 rezultatArray
(
[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 jestArray
(
[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