get_object_vars

(PHP 4, PHP 5, PHP 7, PHP 8)

get_object_vars获取给定对象的属性

描述

get_object_vars(object $object): array

根据作用域获取给定 object 的可访问非静态属性。

参数

object

一个对象实例。

返回值

返回一个关联数组,其中包含指定 object 在作用域内的定义的对象可访问非静态属性。

示例

示例 #1 使用 get_object_vars()

<?php

class foo {
private
$a;
public
$b = 1;
public
$c;
private
$d;
static
$e;

public function
test() {
var_dump(get_object_vars($this));
}
}

$test = new foo;
var_dump(get_object_vars($test));

$test->test();

?>

以上示例将输出

array(2) {
  ["b"]=>
  int(1)
  ["c"]=>
  NULL
}
array(4) {
  ["a"]=>
  NULL
  ["b"]=>
  int(1)
  ["c"]=>
  NULL
  ["d"]=>
  NULL
}

注意:

未初始化的属性被认为是不可访问的,因此不会包含在数组中。

参见

添加笔记

用户贡献笔记 5 个笔记

fmmarzoa at librexpresion dot org
19 年前
您仍然可以将对象强制转换为数组以获取其所有成员并查看其可见性。例如

<?php

class Potatoe {
public
$skin;
protected
$meat;
private
$roots;

function
__construct ( $s, $m, $r ) {
$this->skin = $s;
$this->meat = $m;
$this->roots = $r;
}
}

$Obj = new Potatoe ( 1, 2, 3 );

echo
"<pre>\n";
echo
"使用 get_object_vars:\n";

$vars = get_object_vars ( $Obj );
print_r ( $vars );

echo
"\n\n使用数组转换:\n";

$Arr = (array)$Obj;
print_r ( $Arr );

?>

这将返回

使用 get_object_vars
数组
(
[skin] => 1
)

使用数组转换
数组
(
[skin] => 1
[ * meat] => 2
[ Potatoe roots] => 3
)

如您所见,您可以从此转换中获得每个成员的可见性。那些似乎在数组键中使用空格的是 '\0' 字符,因此解析键的一般规则似乎是

公共成员:member_name
受保护的成员:\0*\0member_name
私有成员:\0Class_name\0member_name

我编写了一个 obj2array 函数,它为每个键创建没有可见性的条目,这样您就可以像在对象中一样在数组中处理它们

<?php

function obj2array ( &$Instance ) {
$clone = (array) $Instance;
$rtn = array ();
$rtn['___SOURCE_KEYS_'] = $clone;

while ( list (
$key, $value) = each ($clone) ) {
$aux = explode ("\0", $key);
$newkey = $aux[count($aux)-1];
$rtn[$newkey] = &$rtn['___SOURCE_KEYS_'][$key];
}

return
$rtn;
}

?>

我还创建了一个 <i>bless</i> 函数,其工作原理类似于 Perl 的 bless,这样您就可以进一步重新转换数组,将其转换为特定类的对象

<?php

function bless ( &$Instance, $Class ) {
if ( ! (
is_array ($Instance) ) ) {
return
NULL;
}

// 首先获取可用的源键
if ( isset ($Instance['___SOURCE_KEYS_'])) {
$Instance = $Instance['___SOURCE_KEYS_'];
}

// 从数组获取序列化数据
$serdata = serialize ( $Instance );

list (
$array_params, $array_elems) = explode ('{', $serdata, 2);
list (
$array_tag, $array_count) = explode (':', $array_params, 3 );
$serdata = "O:".strlen ($Class).":\"$Class\":$array_count:{".$array_elems;

$Instance = unserialize ( $serdata );
return
$Instance;
}
?>

使用这些,您可以执行以下操作

<?php

define
("SFCMS_DIR", dirname(__FILE__)."/..");
require_once (
SFCMS_DIR."/Misc/bless.php");

class
Potatoe {
public
$skin;
protected
$meat;
private
$roots;

function
__construct ( $s, $m, $r ) {
$this->skin = $s;
$this->meat = $m;
$this->roots = $r;
}

function
PrintAll () {
echo
"skin = ".$this->skin."\n";
echo
"meat = ".$this->meat."\n";
echo
"roots = ".$this->roots."\n";
}
}

$Obj = new Potatoe ( 1, 2, 3 );

echo
"<pre>\n";
echo
"Using get_object_vars:\n";

$vars = get_object_vars ( $Obj );
print_r ( $vars );

echo
"\n\nUsing obj2array func:\n";

$Arr = obj2array($Obj);
print_r ( $Arr );

echo
"\n\nSetting all members to 0.\n";
$Arr['skin']=0;
$Arr['meat']=0;
$Arr['roots']=0;

echo
"Converting the array into an instance of the original class.\n";
bless ( $Arr, Potatoe );

if (
is_object ($Arr) ) {
echo
"\$Arr is now an object.\n";
if (
$Arr instanceof Potatoe ) {
echo
"\$Arr is an instance of Potatoe class.\n";
}
}

$Arr->PrintAll();

?>
Trismegiste
1 年前
请注意未初始化属性的隐藏行为。该说明解释了:“未初始化的属性被认为是不可访问的,因此不会包含在数组中。”但这在 PHP 8.1 中并不完全正确。它取决于属性是否具有类型提示。

<?php

class Example
{
public
$untyped;
public
string $typedButNotInitialized;
public ?
string $typedOrNullNotInitialized;
public ?
string $typedOrNullWithDefaultNull = null;
}

var_dump(get_object_vars(new Example()));
?>

将输出

array(2) {
["untyped"]=>
NULL
["typedOrNullWithDefaultNull"]=>
NULL
}

如您所见,只有 "untyped" 和 "typedOrNullWithDefaultNull" 属性被 get_object_vars() 导出。在迁移旧代码并随意添加类型而没有适当的初始化(或默认值)时,您可能会遇到问题,并假设它像旧代码那样默认值为 NULL。

希望对您有所帮助
marcus at marcusball dot me
3 年前
在处理大量对象时,值得注意的是使用 `get_object_vars()` 可能会大幅增加内存使用量。

如果实例化的对象只使用类中的预定义属性,那么 PHP 可以为类属性使用单个哈希表,并为对象属性使用小巧且内存效率高的数组。

如果一个类定义了三个属性(`$foo`、`$bar` 和 `$baz`),那么“PHP 不再需要将数据存储在哈希表中,而是可以认为 `$foo` 是属性 0,`$bar` 是属性 1,`$baz` 是属性 2,然后只将这些属性存储在一个包含三个元素的 C 数组中。这意味着 PHP 只需要一个哈希表来进行类中的属性名到偏移量的映射,并在各个对象中使用内存效率高的 C 数组。”

但是,如果您对这样的对象调用 `get_object_vars()`,那么 PHP 将为该对象构建一个哈希表。如果您有大量对象,并且对所有对象调用 `get_object_vars()`,那么将为每个对象构建一个哈希表,从而导致更多的内存使用量。这可以在这个错误报告中看到:https://bugs.php.net/bug.php?id=79392

这个影响可以在以下示例中看到

<?php
class Example {
public
$foo;
public
$bar;
public
$baz;
}

function
printMem($label) {
$usage = memory_get_usage();
echo
sprintf('%s: %d (%.2f MB)', $label, $usage, $usage / 1000000) . PHP_EOL;
}

printMem('start');

$objects = [];
for (
$i = 0; $i < 20000; $i++) {
$obj = new Example;
$obj->foo = bin2hex(random_bytes(5));
$obj->bar = bin2hex(random_bytes(5));
$obj->baz = bin2hex(random_bytes(5));
$objects[] = $obj;
}

printMem('before get_object_vars');

// 克隆每个对象,并在克隆对象上获取变量
foreach ($objects as $obj) {
$c = clone $obj;
$vars = get_object_vars($c);

// 访问和修改原始对象是可以的。
foreach ($vars as $var => $val) {
$obj->{$var} = strrev($val);
}
}

printMem('get_object_vars using clone');

// 直接在每个对象上获取变量
foreach ($objects as $obj) {
$vars = get_object_vars($obj);

// 即使您没有修改对象,内存也会被使用。
}

printMem('get_object_vars direct access');
?>

此代码的输出为

start: 405704 (0.41 MB)
before get_object_vars: 6512416 (6.51 MB)
get_object_vars using clone: 6033408 (6.03 MB)
get_object_vars direct access: 13553408 (13.55 MB)

简而言之,如果您使用类来避免与哈希表(如关联数组中)相关的额外内存使用,请注意 `get_object_vars()` 将为传递给它的任何对象创建一个哈希表。

这似乎在所有版本的 PHP 中都存在;我在 PHP 5、7 和 8 上测试过。

引号来自 Nikic 的关于数组和哈希表内存使用的博客文章,以及 Github gist“为什么对象(通常)比 PHP 中的数组使用更少的内存”。
niemans at pbsolo dot nl
3 年前
您可以使用匿名类从类内部返回公共变量

public function getPublicVars () {
$me = new class {
function getPublicVars($object) {
return get_object_vars($object);
}
};
return $me->getPublicVars($this);
}

测试脚本

class Test {
protected $protected;
public $public;
private $private;
public function getAllVars () {
return call_user_func('get_object_vars', $this);
}
public function getPublicVars () {
$me = new class {
function getPublicVars($object) {
return get_object_vars($object);
}
};
return $me->getPublicVars($this);
}
}

$test = new Test();
print_r(get_object_vars($test)); // array("public" => NULL)
print_r($test->getAllVars()); // array("protected" => NULL, "public" => NULL, "private" => NULL)
print_r($test->getPublicVars()); // array("public" => NULL)
Fabien Haddadi
12 年前
似乎没有函数可以确定类的所有 *静态* 变量。

我在项目中需要这个功能,于是写出了以下代码

<?php
function get_class_static_vars($object) {
return
array_diff(get_class_vars(get_class($object)), get_object_vars($object));
}
?>

它依赖于一个有趣的特性:`get_object_vars` 只返回对象的非静态变量。
To Top