使用数字键作为对象转换数组

Ala*_*orm 12 php arrays casting

我在探讨PHP的构建机制,并在将数组作为对象进行投射时遇到了一个奇怪的情况

$o = (object) array('1'=>'/foo/bar');   
$o = new stdClass();
var_dump($o);
Run Code Online (Sandbox Code Playgroud)

据我了解,PHP属性需要使用与PHP变量相同的规则声明.这是一个有效的变量名称,以字母或下划线开头,后跟任意数量的字母,数字或下划线.但是,上面的代码产生以下输出

object(stdClass)#1 (1) {
  [1]=>
  string(8) "/foo/bar"
}
Run Code Online (Sandbox Code Playgroud)

当你试图访问对象中的信息时,它变得非常奇怪.

var_dump($o->1);        // parse error
var_dump($o->{'1'});        // NULL 
var_dump(get_object_vars($o));  //array(0) { }
Run Code Online (Sandbox Code Playgroud)

无论如何都要获取var_dump报告的信息在对象中,或者它是否仅在请求生命周期的其余部分被锁定?(实际使用这是零,我只是好奇)

Der*_*sed 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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:只是对这个假设做了一个更快速的测试,是的,它们在对象上下文中正式"不存在"; 数据存储,但无法访问,因此是最终的私人成员.这是测试:

$a = array('one','two','three');
$o = (object)$a;
var_dump(property_exists($o, 1), property_exists($o, '1'));
Run Code Online (Sandbox Code Playgroud)

输出是:

bool(false)
bool(false)
Run Code Online (Sandbox Code Playgroud)

再次编辑:有趣的附注,以下操作返回false:

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

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

var_dump($y == $z);
Run Code Online (Sandbox Code Playgroud)

  • 这__实际上是[一个bug](https://bugs.php.net/bug.php?id=45959).它一直被认为"修理起来太昂贵",并且解决方案已经"更新了文档来描述这个无用的怪癖,所以它现在是正式的正确行为". (2认同)

rre*_*ein 7

似乎ArrayObject类可以访问属性

$a = new ArrayObject($obj);
echo $a[0];
Run Code Online (Sandbox Code Playgroud)