将具有数字键的数组转换为对象

12

我正在研究PHP的类型转换机制,并在将数组强制转换为对象时遇到了一个奇怪的情况。

$o = (object) array('1'=>'/foo/bar');   
$o = new stdClass();
var_dump($o);

据我理解,PHP属性需要按照与PHP变量相同的规则声明。也就是说,一个有效的变量名以字母或下划线开头,后面可以跟任意数量的字母、数字或下划线。然而,上述代码会产生以下输出:

object(stdClass)#1 (1) {
  [1]=>
  string(8) "/foo/bar"
}

当你尝试在对象中访问该信息时,情况变得非常奇怪。

var_dump($o->1);        // parse error
var_dump($o->{'1'});        // NULL 
var_dump(get_object_vars($o));  //array(0) { }

有没有办法获取var_dump报告的对象信息,或者它只是在请求生命周期的其余时间中被锁定了?(这个问题实际上没有实际用途,我只是好奇)


从我的经验来看,尽管我从未坚定到尝试一切,但它们似乎被锁起来了。 - jlb
实际上,这是PHP中已知的问题。 - GSto
这个“known”是指我们所知道的,还是指PHP团队在某种程度上承认的? - Alana Storm
4个回答

14

是的,它们只是被锁定起来,除非将其转换为数组。PHP中有一些小的“陷阱”,例如在旧版本中,您可以将常量定义为数组,但从未访问其元素。即使现在,您也可以将常量定义为资源(例如define('MYSQL',mysql_connect());),但这会导致相当不可预测的行为,因此应该避免。

通常,最好尽可能避免数组到对象的强制转换。如果确实需要这样做,请考虑创建一个stdClass类的新实例,然后手动重命名所有变量,例如_0_1等。

$a = array('cat','dog','pheasant');
$o = new stdClass;
foreach ($a as $k => $v) {
    if (is_numeric($k)) {
        $k = "_{$k}";
    }
    $o->$k = $v;
}

编辑:我刚刚对这个假设进行了一个快速的测试,是的,在对象上下文中它们正式“不存在”;数据已经存储,但无法访问,因此它是终极私有成员。以下是测试:

$a = array('one','two','three');
$o = (object)$a;
var_dump(property_exists($o, 1), property_exists($o, '1'));

输出结果为:

bool(false)
bool(false)

再次编辑:有趣的副作用是,下面的操作会返回false:

$a = array('one','two','three','banana' => 'lime');
$b = array('one','two','banana' => 'lime');

$y = (object)$a;
$z = (object)$b;

var_dump($y == $z);

2
这实际上是一个错误。它被认为是“修复成本太高”,解决方案是“更新文档以描述这个无用的怪癖,因此现在是官方正确的行为”。 - lanzz

7

看起来ArrayObject类可以访问属性

$a = new ArrayObject($obj);
echo $a[0];

1

是的,它们只是被锁定,除非重新转换为数组。

也许属性仍然存在并且可访问,只是不能直接访问。但是,我不确定foreach如何在内部工作(它可能将对象转换为数组),因为我没有深入研究源代码。

示例:

$array = array('one', 'two', 'three', 'four');
$obj = (object) $array;

foreach ($obj as $key => &$val) {
    print "$key -> $val<br>";
    $val = 'Nhaca';
    var_dump($obj);
}
print_r($obj);
print_r($array);

输出:

0 -> one
object(stdClass)[1]
  &string 'Nhaca' (length=5)
  string 'two' (length=3)
  string 'three' (length=5)
  string 'four' (length=4)
1 -> two
object(stdClass)[1]
  string 'Nhaca' (length=5)
  &string 'Nhaca' (length=5)
  string 'three' (length=5)
  string 'four' (length=4)
2 -> three
object(stdClass)[1]
  string 'Nhaca' (length=5)
  string 'Nhaca' (length=5)
  &string 'Nhaca' (length=5)
  string 'four' (length=4)
3 -> four
object(stdClass)[1]
  string 'Nhaca' (length=5)
  string 'Nhaca' (length=5)
  string 'Nhaca' (length=5)
  &string 'Nhaca' (length=5)
stdClass Object ( [0] => Nhaca [1] => Nhaca [2] => Nhaca [3] => Nhaca ) 
Array ( [0] => one [1] => two [2] => three [3] => four )

0

我认为你会遇到一个错误,因为将数组的整数键转换为对象/子对象会破坏PHP变量的命名约定。

提示:

  • 事先决定您想要一个OBJECT还是一个ARRAY
  • 小心类型转换(例如(object)array(1 =&gt;'string')不要这样做)
  • 使用强制转换进行验证而不是转换内容
  • 避免将对象用作“伪”数组

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接