广告

PHP 中 json_encode 编码对象属性的原理与实战:哪些属性会被编码以及常见坑点

1. 原理与编码行为

1.1 公共属性的编码规则

在 PHP 的 json_encode 编码对象时,默认只编码对象的公共属性。这意味着私有(private)和受保护(protected)属性不会直接出现在 JSON 输出中,除非通过特定方式暴露或自定义序列化逻辑来输出它们。

如果对象中存在公共属性,json_encode 会将它们作为 JSON 对象的键值对输出,键名对应属性名,键值对应该属性的值。对于包含其他对象或数组的属性,编码会进行递归处理,遵循相同的规则。

class User {public $name;private $password;protected $role;public function __construct($name, $password, $role) {$this->name = $name;$this->password = $password;$this->role = $role;}
}$user = new User('张三', 'secret', 'admin');
echo json_encode($user);
// 输出通常仅包含 { "name": "张三" },私有与受保护属性不会出现在结果中

1.2 JsonSerializable 与 jsonSerialize

JsonSerializable 接口提供了自定义编码的入口点,实现 jsonSerialize() 方法后,json_encode 会调用该方法返回的数据作为输出对象。这让你能够明确控制哪些字段被编码,以及如何编码。

如果对象实现了 JsonSerializable,那么即使对象内部有私有或受保护属性,也能通过 jsonSerialize() 输出自定义结构,从而实现更精细的权限控制和数据格式化。

class User implements JsonSerializable {public $name;private $password;protected $role;public function __construct($name, $password, $role) {$this->name = $name;$this->password = $password;$this->role = $role;}public function jsonSerialize() {// 显式输出想要暴露的字段return ['name' => $this->name,'role' => $this->role];}
}
$user = new User('张三', 'secret', 'admin');
echo json_encode($user); // {"name":"张三","role":"admin"}

2. 哪些属性会被编码与常见坑点

2.1 公共属性的可编码性与 get_object_vars

json_encode 的编码对象行为建立在对可访问属性的遍历之上,get_object_vars($obj) 只返回对象的公共属性,这也是 json_encode 在底层进行编码时的核心依据。

若想在编码前查看当前对象有哪些可编码的公开字段,可以使用 var_dumpget_object_vars 来查看。

class Sample {public $a = 1;private $b = 2;
}
$x = new Sample();
echo json_encode($x); // 仅输出 {"a":1}

2.2 私有与保护属性如何编码

除非通过实现 JsonSerializable 或改为公开属性,否则私有/受保护属性不会出现在 JSON 中。这也是一个常见坑点:以为所有成员都会被编码,结果缺少字段。

class Demo {private $secret = 'top';protected $token = 'abc';
}
$d = new Demo();
echo json_encode($d); // 输出:{}

要包含私有/受保护属性,可以选择以下路径:

  • 实现 JsonSerializable,在 jsonSerialize() 中输出需要的字段
  • 将需要暴露的字段改为公开属性(注意避免暴露敏感信息)

2.3 循环引用与编码错误的处理

对象之间存在循环引用时,直接 json_encode 可能导致错误或崩溃。为避免递归导致的问题,建议避免直接的循环引用,或通过 JsonSerializable 返回扁平化的结构

class Node {public $value;public $next;
}
$a = new Node(); $b = new Node(); $a->next = $b; $b->next = $a;
echo json_encode($a); // 可能触发递归问题

2.4 Unicode 与编码选项

json_encode 的默认行为可能会对 Unicode 字符进行转义,使用 JSON_UNESCAPED_UNICODE 可以避免转义,从而提高可读性,尤其在国际化场景下对 SEO 友好性有帮助。

echo json_encode($user, JSON_UNESCAPED_UNICODE); // 直接输出中文

3. 实战技巧:结合 JsonSerializable 的最佳实践

3.1 自定义编码输出的清晰结构

在真实项目中,推荐使用 JsonSerializable 接口来控制输出结构,避免暴露敏感字段,同时提升前端对数据结构的稳定性。

class Product implements JsonSerializable {public $id;public $name;private $price;protected $stock;public function __construct($id, $name, $price, $stock) {$this->id = $id;$this->name = $name;$this->price = $price;$this->stock = $stock;}public function jsonSerialize() {return ['id' => $this->id,'name' => $this->name,'price' => $this->price// stock 不输出];}
}
$p = new Product(101, '摄像头', 299.99, 20);
echo json_encode($p, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

3.2 与数据库对象的整合注意点

从数据库层取出的数据通常映射为 DTO 或视图模型,再通过 JsonSerializable 将其转换为 JSON,以降低耦合并提升安全性。

// 假设从数据库取出一个行数据映射到对象
class UserDTO implements JsonSerializable {public $id;public $name;private $passwordHash;public function __construct($id, $name, $passwordHash) {$this->id = $id;$this->name = $name;$this->passwordHash = $passwordHash;}public function jsonSerialize() {return ['id' => $this->id,'name' => $this->name];}
}

重点提醒:不要无条件暴露数据库字段,保护敏感信息是后端的基本职责。

3.3 实战要点与应用场景

在实际项目中,按照需求选择输出字段、控制敏感信息暴露、再结合编码选项(如 JSON_UNESCAPED_UNICODEJSON_PRETTY_PRINT),能够形成稳定的前后端数据接口,并便于后续维护。

核心要点:通过实现 JsonSerializable 或公开字段,搭配显式输出结构以及适当的编码选项,确保 Object 属性在 JSON 中的可控性与安全性。

PHP 中 json_encode 编码对象属性的原理与实战:哪些属性会被编码以及常见坑点

广告

后端开发标签