【问题标题】:Casting an Array with Numeric Keys as an Object将带有数字键的数组转换为对象
【发布时间】:2010-12-24 14:20:49
【问题描述】:

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

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

据我了解,PHP 属性需要使用与 PHP 变量相同的规则进行声明。那是A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores。但是,上面的代码会产生以下输出

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 报告的信息在对象中,还是在请求生命周期的剩余时间里被锁定? (实际使用为零,我只是好奇)

【问题讨论】:

  • 根据我的经验,它们似乎被锁起来了,尽管我从来没有足够坚定地尝试一切。
  • 事实上是这样,这是 PHP 中的一个已知问题。
  • 是我们已知的,还是 PHP 团队以某种方式承认的。

标签: php arrays casting


【解决方案1】:

是的,除非将它们转换回数组,否则它们只是被锁定。 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)

再次编辑:有趣的旁注,以下操作返回错误:

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

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

var_dump($y == $z);

【讨论】:

  • 这个实际上是a bug。它被认为“修复成本太高”,解决方案已“更新了文档以描述这种无用的怪癖,因此现在正式正确的行为”。
【解决方案2】:

看来 ArrayObject 类可以访问属性

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

【讨论】:

    【解决方案3】:

    是的,除非将它们转换回数组,否则它们只是被锁定。

    也许,这些属性仍然存在并且可以访问,只是不能直接访问。但是,我不确定 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 )
    

    【讨论】:

      【解决方案4】:

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

      提示:

      • 在动手之前决定您是想要OBJECT 还是ARRAY
      • 小心类型转换(例如,(object) array(1=>'string') 不要做这样的事情)
      • 使用铸件进行验证,而不是转换内容
      • 避免将对象用作“假”数组

      【讨论】:

        猜你喜欢
        • 2014-01-19
        • 1970-01-01
        • 2019-06-20
        • 2016-07-05
        • 2021-02-17
        • 2018-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多