PHP Conference Japan 2024

get_object_vars

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

get_object_vars获取给定对象的属性

描述

get_object_vars(对象 $object): 数组

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

参数

object

一个对象实例。

返回值

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

示例

示例 #1 get_object_vars() 的用法

<?php

foo {
私有
$a;
公共
$b = 1;
公共
$c;
私有
$d;
静态
$e;

公共函数
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
20 年前
您仍然可以将对象转换为数组以获取其所有成员并查看其可见性。示例

<?php

Potatoe {
公共
$skin;
受保护
$meat;
私有
$roots;

函数
__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

函数 obj2array ( &$Instance ) {
$clone = (array) $Instance;
$rtn = 数组 ();
$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
"使用 get_object_vars:\n";

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

echo
"\n\n使用 obj2array 函数:\n";

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

echo
"\n\n将所有成员设置为 0。\n";
$Arr['skin']=0;
$Arr['meat']=0;
$Arr['roots']=0;

echo
"将数组转换为原始类的实例。\n";
bless ( $Arr, Potatoe );

if (
is_object ($Arr) ) {
echo
"\$Arr 现在是一个对象。\n";
if (
$Arr instanceof Potatoe ) {
echo
"\$Arr 是 Potatoe 类的实例。\n";
}
}

$Arr->PrintAll();

?>
Trismegiste
2 年前
请注意未初始化属性的隐藏行为。注释中解释道:“未初始化的属性被认为是不可访问的,因此不会包含在数组中。”但对于 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
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('开始');

$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('调用 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');

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

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

printMem('直接访问 get_object_vars');
?>

此代码的输出结果为

开始: 405704 (0.41 MB)
调用 get_object_vars 之前: 6512416 (6.51 MB)
使用克隆调用 get_object_vars: 6033408 (6.03 MB)
直接访问 get_object_vars: 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