如何将对象转换为数组并剔除默认值

1次阅读

如何将对象转换为数组并剔除默认值

本文介绍一种可靠方法,将 php 对象实例转换为关联数组,并自动过滤掉所有与类定义中初始值相同的属性(即“默认值”),仅保留被显式修改过的字段,适用于数据库存储前的数据精简。

php 中,直接使用 (Array) 强制类型转换虽能将对象转为数组,但存在明显局限:它会保留所有属性(包括未赋值的 NULL、空数组或字符串默认值),且无法区分“用户显式设置”与“继承自类定义的默认值”。更关键的是,当属性值为数组或对象时,array_diff() 会因不支持递归比较而抛出 Array to String conversion 错误。

理想的解决方案是显式获取类的默认状态快照,并与当前实例逐属性比对。以下是一个健壮、可复用的实现方式:

✅ 推荐实现(基于反射 + 属性比对)

class MyObject {     public $title = null;     public $description = null;     public $items = [];     public $metas = [];     public $image = null;     public $country = 'Belgium';     // 注意:$children 不在原始类定义中,但运行时被动态添加 → 需保留!      /**      * 获取当前实例所有 public 属性的默认初始值(静态快照)      */     public function getDefaultValues(): array {         $reflect = new ReflectionClass($this);         $props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);          $defaults = [];         foreach ($props as $prop) {             $name = $prop->getName();             // 使用 ReflectionProperty::getDefaultValue() 更准确(PHP 8.0+)             // 此处兼容旧版:通过新实例获取初始值             $defaults[$name] = $prop->getDefaultValue() ?? null;         }         return $defaults;     }      /**      * 获取当前实例中「非默认值」的属性,返回精简数组      */     public function toArrayWithoutDefaults(): array {         $defaults = $this->getDefaultValues();         $current = [];          // 手动收集当前所有 public 属性(含动态添加项)         foreach (get_object_vars($this) as $key => $value) {             $current[$key] = $value;         }          $result = [];         foreach ($current as $key => $value) {             // 判断是否为默认值(支持 null、[]、字符串等基础类型)             $isDefault = array_key_exists($key, $defaults)                 ? $this->deepEqual($value, $defaults[$key])                 : false;              if (!$isDefault) {                 $result[$key] = $value;             }         }         return $result;     }      /**      * 深度比较两个值(简化版,支持 null、标量、数组)      */     private function deepEqual($a, $b): bool {         if (is_array($a) && is_array($b)) {             return $a === $b; // PHP 数组全等已支持深度比较         }         return $a === $b;     } }

? 使用示例

$data = new MyObject(); $data->title = 'NEW ITEM'; $data->children = ['CHILD1', 'CHILD2']; // 动态属性,不在类定义中 → 自动保留 $data->image = 'image.gif'; $data->country = 'Belgium'; // 与默认值相同 → 被剔除  $dataToStore = $data->toArrayWithoutDefaults(); print_r($dataToStore);

输出结果:

Array (     [title] => NEW ITEM     [children] => Array         (             [0] => CHILD1             [1] => CHILD2         )     [image] => image.gif )

⚠️ 注意事项

  • 动态属性支持:get_object_vars() 可捕获运行时新增的 public 属性(如 $data->children),而 ReflectionClass::getProperties() 仅返回类定义中的属性。因此本方案兼顾灵活性与准确性。
  • 类型安全比对:使用 ===(全等)而非 ==,避免 ‘0’ == 0 类型隐式转换导致误判。
  • 性能考量:反射操作有轻微开销,若高频调用,可将 getDefaultValues() 结果缓存于静态属性。
  • 扩展建议:如需支持 private/protected 属性,需配合 setaccessible(true);若需 jsON 序列化兼容,可实现 jsonSerializable 接口

该方法逻辑清晰、无副作用、兼容主流 PHP 版本(7.4+),是生产环境中安全可靠的“默认值剥离”实践方案。

text=ZqhQzanResources