Как стать автором
Обновить

Как получить доступ ко всем свойствам объекта, не используя «отражение»

Время на прочтение3 мин
Количество просмотров12K
Для чего получать доступ ко всем свойствам объекта и при этом не менять его интерфейс? Например, для того, чтобы написать свою сериализацию. Или чтобы передать объект в приемлемом виде используя http. Или для чего-нибудь ещё.

Возьмём для эксперимента простой класс.

class aClass
    {
    protected $protected_property = 'protected_value';
    private $private_property = 'private_value';
    public $public_property = 'public_value';
    }

$an_object = new aClass;

var_dump($an_object);
//    object(aClass)#1 (3) {
//      ["protected_property":protected]=>
//      string(15) "protected_value"
//      ["private_property":"aClass":private]=>
//      string(13) "private_value"
//      ["public_property"]=>
//      string(12) "public_value"
//    }


Если использовать «отражение», то получить все свойства объекта можно, например, вот таким способом.

$an_array = array();
$reflection = new ReflectionClass($an_object);
$properties = $reflection->getProperties();
foreach ($properties as $property)
    {
    $property->setAccessible(true);
    $an_array[$property->getName()] = $property->getValue($an_object);
    if (!$property->isPublic())
        $property->setAccessible(false);
    }

var_dump($an_array);
//    array(3) {
//      ["protected_property"]=>
//      string(15) "protected_value"
//      ["private_property"]=>
//      string(13) "private_value"
//      ["public_property"]=>
//      string(12) "public_value"
//    }


Есть более простой способ получить все свойства в виде массива.

$an_array = (array) $an_object;

var_dump($an_array);
//    array(3) {
//      ["�*�protected_property"]=>
//      string(15) "protected_value"
//      ["�aClass�private_property"]=>
//      string(13) "private_value"
//      ["public_property"]=>
//      string(12) "public_value"
//    }


Получилось немного «грязновато», если надо, то можно очистить ключи от лишних данных. Например, вот так:

$key = ($key{0} === "\0") ? substr($key, strpos($key, "\0", 1) + 1) : $key;


Кстати, обратный трюк с преобразованием массива в объект не сработает. Таким образом можно получить только объект stdClass.

$an_another_object = (object) $an_array;

var_dump($an_another_object);
//    object(stdClass)#6 (3) {
//      ["protected_property":protected]=>
//      string(15) "protected_value"
//      ["private_property":"aClass":private]=>
//      string(13) "private_value"
//      ["public_property"]=>
//      string(12) "public_value"
//    }


Есть ещё недокументированный способ получения свойств. Этот способ даже похоже на баг, но таким не является, поэтому его можно смело использовать.

$an_array = array();
reset($an_object);
while (list($key, $val) = each($an_object))
    $an_array[$key] = $val;

var_dump($an_array);
//    array(3) {
//      ["�*�protected_property"]=>
//      string(15) "protected_value"
//      ["�aClass�private_property"]=>
//      string(13) "private_value"
//      ["public_property"]=>
//      string(12) "public_value"
//    }


В свою очередь, чтобы установить новое значение для произвольного свойства (в том числе и приватного), можно использовать уже другой недокументированный приём.

$an_array["\0aClass\0private_property"] = 'new_private_value';
array_walk($an_object, function(&$val, $key, $array){$val = $array[$key];}, $an_array);

var_dump($an_object);
//    object(aClass)#1 (3) {
//      ["protected_property":protected]=>
//      string(15) "protected_value"
//      ["private_property":"aClass":private]=>
//      string(17) "new_private_value"
//      ["public_property"]=>
//      string(12) "public_value"
//    }


Заключение

Используя тот или иной случай помните, что таким способом вы вероломно вторгаетесь в защищённую область объекта, тем самым обходите все выставленные защиты в виде protected или private, а объект об этом даже ничего и не узнает. Поэтому, если есть возможность, то лучше сделать специальные методы доступа.
Теги:
Хабы:
Всего голосов 23: ↑13 и ↓10+3
Комментарии21

Публикации

Истории

Работа

PHP программист
148 вакансий

Ближайшие события

Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург