PHP如何直接访问stdClass对象的整数键名公共属性
问题背景
我更倾向于使用对象语法访问关联数组,即相较于$arr['item_title']的数组下标访问写法,我更偏好使用$arr->item_title的对象属性访问写法。我编写了如下逻辑生成数组后,通过强制类型转换将其转换为对象:
public function getTotal() { $total = 0; $items = []; $i = 0; $val = ($this->type == 'PUR')? 'cost': 'price'; foreach($this->invoiceItems as $item){ $items[$i]['item_title'] = $item->item->title; $items[$i]['item_id'] = $item->item_id; $items[$i]['unit_title'] = $item->unit->title; $items[$i]['unit_id'] = $item->unit_id; $items[$i]['cost'] = $item->itemUnit->cost; $items[$i]['price'] = $item->itemUnit->price; $items[$i]['qty'] = $item->qty; $total = $total + ($item->qty*$item->itemUnit->${'val'}) ; $i++; } $output['total'] = $total; $output['items'] = (object) $items; $this->setTotal((object) $output); return $this->_total; }
转换完成后生成的对象结构示例如下(通过var_dump打印输出):
<?= var_dump($model->total->items);?> object(stdClass)[117] public '0' => array (size=7) 'item_title' => string 'Aspoceed tab.' (length=13) 'item_id' => int 2 'unit_title' => string 'Packet2s-10' (length=11) 'unit_id' => int 3 'cost' => float 9.25 'price' => float 10 'qty' => int 2 public '1' => array (size=7) 'item_title' => string 'Aspoceed tab.' (length=13) 'item_id' => int 2 'unit_title' => string 'Strip10' (length=7) 'unit_id' => int 2 'cost' => float 4.75 'price' => float 5.25 'qty' => int 1 public '2' => array (size=7) 'item_title' => string 'Apidone' (length=7) 'item_id' => int 3 'unit_title' => string 'Bottle Pack 12' (length=14) 'unit_id' => int 6 'cost' => float 118 'price' => float 121.75 'qty' => int 2
遇到的问题
无法在不通过循环遍历的前提下直接访问上述对象的公共属性,尝试以下几种访问写法均返回错误:
$model->total->items->['0']->item_title // OR $model->total->items->[0]->item_title // OR $model->total->items[0]->item_title // OR $model->total->items['0']->item_title
核心疑问:是否可以直接访问通过上述方式创建的对象?如果可以,正确的访问写法是什么?
解答
可以直接访问该方式创建的对象,之前访问失败有两个核心原因:
- 数字索引数组强转为stdClass对象后,数字键名会成为对象的公开属性,但这类数字命名的属性无法直接通过
->后跟字面量数字/字符串数字的方式读取,必须用花括号包裹键名的特殊语法访问 - 现有结构中
0/1/2这类属性对应的值仍然是数组类型,不是对象,因此读取到该层级后,需要用数组下标语法访问子元素,不能直接用->调用属性
现有结构的正确访问写法
// 访问第一条数据的item_title字段 $model->total->items->{0}['item_title']; // 字符串格式数字键名写法效果完全一致 $model->total->items->{'0'}['item_title'];
统一对象语法访问的优化方案
如果需要全程使用对象属性语法访问所有层级,可以在生成子项时就将每个子项数组也强制转换为对象,修改原循环内的赋值逻辑即可:
foreach($this->invoiceItems as $item){ $items[$i] = (object)[ 'item_title' => $item->item->title, 'item_id' => $item->item_id, 'unit_title' => $item->unit->title, 'unit_id' => $item->unit_id, 'cost' => $item->itemUnit->cost, 'price' => $item->itemUnit->price, 'qty' => $item->qty ]; $total = $total + ($item->qty*$item->itemUnit->${'val'}) ; $i++; }
修改完成后所有层级均为stdClass对象,可统一用对象语法访问:
$model->total->items->{0}->item_title;
内容的提问来源于stack exchange,提问作者SaidbakR
相关产品推荐
相关产品推荐

