Для чего получать доступ ко всем свойствам объекта и при этом не менять его интерфейс? Например, для того, чтобы написать свою сериализацию. Или чтобы передать объект в приемлемом виде используя http. Или для чего-нибудь ещё.
Возьмём для эксперимента простой класс.
Если использовать «отражение», то получить все свойства объекта можно, например, вот таким способом.
Есть более простой способ получить все свойства в виде массива.
Получилось немного «грязновато», если надо, то можно очистить ключи от лишних данных. Например, вот так:
Кстати, обратный трюк с преобразованием массива в объект не сработает. Таким образом можно получить только объект stdClass.
Есть ещё недокументированный способ получения свойств. Этот способ даже похоже на баг, но таким не является, поэтому его можно смело использовать.
В свою очередь, чтобы установить новое значение для произвольного свойства (в том числе и приватного), можно использовать уже другой недокументированный приём.
Заключение
Используя тот или иной случай помните, что таким способом вы вероломно вторгаетесь в защищённую область объекта, тем самым обходите все выставленные защиты в виде protected или private, а объект об этом даже ничего и не узнает. Поэтому, если есть возможность, то лучше сделать специальные методы доступа.
Возьмём для эксперимента простой класс.
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, а объект об этом даже ничего и не узнает. Поэтому, если есть возможность, то лучше сделать специальные методы доступа.