所以当我偶然发现新的php.net时,我正在JsonSerializable Interface四处寻找有关将PHP对象序列化为JSON的信息。它只有 PHP> = 5.4 ,而且我在5.3.x环境中运行。
如何实现这种功能 PHP< 5.4
我还没有使用JSON,但我正在尝试在应用程序中支持API层,并将数据对象(以其他方式发送到视图)转储到JSON将是完美的。
如果我尝试直接序列化对象,它会返回一个空的JSON字符串;这是因为我认为json_encode()
不知道对该对象做什么。我是否应该递归地将对象缩减为数组,然后编码 ?
$data = new Mf_Data();
$data->foo->bar['hello'] = 'world';
echo json_encode($data)
会产生一个空对象:
{}
var_dump($data)
然而,按预期工作:
object(Mf_Data)#1 (5) {
["_values":"Mf_Data":private]=>
array(0) {
}
["_children":"Mf_Data":private]=>
array(1) {
[0]=>
array(1) {
["foo"]=>
object(Mf_Data)#2 (5) {
["_values":"Mf_Data":private]=>
array(0) {
}
["_children":"Mf_Data":private]=>
array(1) {
[0]=>
array(1) {
["bar"]=>
object(Mf_Data)#3 (5) {
["_values":"Mf_Data":private]=>
array(1) {
[0]=>
array(1) {
["hello"]=>
string(5) "world"
}
}
["_children":"Mf_Data":private]=>
array(0) {
}
["_parent":"Mf_Data":private]=>
*RECURSION*
["_key":"Mf_Data":private]=>
string(3) "bar"
["_index":"Mf_Data":private]=>
int(0)
}
}
}
["_parent":"Mf_Data":private]=>
*RECURSION*
["_key":"Mf_Data":private]=>
string(3) "foo"
["_index":"Mf_Data":private]=>
int(0)
}
}
}
["_parent":"Mf_Data":private]=>
NULL
["_key":"Mf_Data":private]=>
NULL
["_index":"Mf_Data":private]=>
int(0)
}
所以这是我为toArray()
课程设计的Mf_Data
函数:
public function toArray()
{
$array = (array) $this;
array_walk_recursive($array, function (&$property) {
if ($property instanceof Mf_Data) {
$property = $property->toArray();
}
});
return $array;
}
但是,由于Mf_Data
对象也有对其父对象(包含)的引用,因此递归失败。当我删除_parent
引用时,它就像一个魅力。
为了跟进,我改造的复杂树节点对象的最终函数是:
// class name - Mf_Data
// exlcuded properties - $_parent, $_index
public function toArray()
{
$array = get_object_vars($this);
unset($array['_parent'], $array['_index']);
array_walk_recursive($array, function (&$property) {
if (is_object($property) && method_exists($property, 'toArray')) {
$property = $property->toArray();
}
});
return $array;
}
我再次跟进,有点清洁的实现。使用instanceof
检查的接口似乎比method_exists()
更清晰(但是method_exists()
横切继承/实现)。
使用unset()
似乎也有点混乱,似乎逻辑应该重构为另一种方法。但是,此实现 复制属性数组(归因于array_diff_key
),因此需要考虑。
interface ToMapInterface
{
function toMap();
function getToMapProperties();
}
class Node implements ToMapInterface
{
private $index;
private $parent;
private $values = array();
public function toMap()
{
$array = $this->getToMapProperties();
array_walk_recursive($array, function (&$value) {
if ($value instanceof ToMapInterface) {
$value = $value->toMap();
}
});
return $array;
}
public function getToMapProperties()
{
return array_diff_key(get_object_vars($this), array_flip(array(
'index', 'parent'
)));
}
}
答案 0 :(得分:88)
在最简单的情况下,类型提示应该有效:
$json = json_encode( (array)$object );
答案 1 :(得分:43)
编辑:目前是2016-09-24,PHP 5.4已发布2012-03-01,支持已结束 2015-09-01。不过,这个答案似乎得到了回报。如果你还在使用PHP< 5.4,您正在制造安全风险并终结您的项目。如果您没有令人信服的理由留在< 5.4,或者甚至已经使用版本> = 5.4,不要使用此答案,只需使用PHP> = 5.4(或者,您知道,最近的一个)并实施the JsonSerializable interface
您将定义一个函数,例如名为getJsonData();
的函数,该函数将返回数组,stdClass
对象或具有可见参数的其他对象,而不是私有/受保护的对象,并执行{ {1}}。本质上,从5.4实现函数,但手动调用。
这样的东西会起作用,因为从类内部调用json_encode($data->getJsonData());
,可以访问私有/受保护的变量:
get_object_vars()
答案 2 :(得分:19)
json_encode()
只会编码公共成员变量。因此,如果您想要自己包括私人(如其他人所建议的那样)
答案 3 :(得分:7)
以下代码正在使用反射来完成工作。它假定您有要序列化的属性的getter
<?php
/**
* Serialize a simple PHP object into json
* Should be used for POPO that has getter methods for the relevant properties to serialize
* A property can be simple or by itself another POPO object
*
* Class CleanJsonSerializer
*/
class CleanJsonSerializer {
/**
* Local cache of a property getters per class - optimize reflection code if the same object appears several times
* @var array
*/
private $classPropertyGetters = array();
/**
* @param mixed $object
* @return string|false
*/
public function serialize($object)
{
return json_encode($this->serializeInternal($object));
}
/**
* @param $object
* @return array
*/
private function serializeInternal($object)
{
if (is_array($object)) {
$result = $this->serializeArray($object);
} elseif (is_object($object)) {
$result = $this->serializeObject($object);
} else {
$result = $object;
}
return $result;
}
/**
* @param $object
* @return \ReflectionClass
*/
private function getClassPropertyGetters($object)
{
$className = get_class($object);
if (!isset($this->classPropertyGetters[$className])) {
$reflector = new \ReflectionClass($className);
$properties = $reflector->getProperties();
$getters = array();
foreach ($properties as $property)
{
$name = $property->getName();
$getter = "get" . ucfirst($name);
try {
$reflector->getMethod($getter);
$getters[$name] = $getter;
} catch (\Exception $e) {
// if no getter for a specific property - ignore it
}
}
$this->classPropertyGetters[$className] = $getters;
}
return $this->classPropertyGetters[$className];
}
/**
* @param $object
* @return array
*/
private function serializeObject($object) {
$properties = $this->getClassPropertyGetters($object);
$data = array();
foreach ($properties as $name => $property)
{
$data[$name] = $this->serializeInternal($object->$property());
}
return $data;
}
/**
* @param $array
* @return array
*/
private function serializeArray($array)
{
$result = array();
foreach ($array as $key => $value) {
$result[$key] = $this->serializeInternal($value);
}
return $result;
}
}
答案 4 :(得分:5)
只需实现PHP JsonSerializable给出的接口。
答案 5 :(得分:2)
由于您的对象类型是自定义的,我倾向于同意您的解决方案 - 使用编码方法(如JSON或序列化内容)将其分解为较小的段,并在另一端具有相应的代码以进行重构对象。
答案 6 :(得分:1)
我的版本:
json_encode(self::toArray($ob))
实现:
private static function toArray($object) {
$reflectionClass = new \ReflectionClass($object);
$properties = $reflectionClass->getProperties();
$array = [];
foreach ($properties as $property) {
$property->setAccessible(true);
$value = $property->getValue($object);
if (is_object($value)) {
$array[$property->getName()] = self::toArray($value);
} else {
$array[$property->getName()] = $value;
}
}
return $array;
}
JsonUtils:GitHub
答案 7 :(得分:1)
尝试使用它,对我来说效果很好。
json_encode(unserialize(serialize($array)));
答案 8 :(得分:0)
我做了一个很好的帮助器类,它将带有get方法的对象转换为数组。 它不依赖于属性,只依赖于方法。
所以我有一个以下评论对象,其中包含两个方法:
查看强>
<强>注释强>
我编写的脚本会将其转换为具有如下属性的数组:
{
amount_reviews: 21,
reviews: [
{
subject: "In een woord top 1!",
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque laoreet lacus quis eros venenatis, sed tincidunt mi rhoncus. Aliquam ut pharetra diam, nec lobortis dolor."
},
{
subject: "En een zwembad 2!",
description: "Maecenas et aliquet mi, a interdum mauris. Donec in egestas sem. Sed feugiat commodo maximus. Pellentesque porta consectetur commodo. Duis at finibus urna."
},
{
subject: "In een woord top 3!",
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque laoreet lacus quis eros venenatis, sed tincidunt mi rhoncus. Aliquam ut pharetra diam, nec lobortis dolor."
},
{
subject: "En een zwembad 4!",
description: "Maecenas et aliquet mi, a interdum mauris. Donec in egestas sem. Sed feugiat commodo maximus. Pellentesque porta consectetur commodo. Duis at finibus urna."
},
{
subject: "In een woord top 5!",
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque laoreet lacus quis eros venenatis, sed tincidunt mi rhoncus. Aliquam ut pharetra diam, nec lobortis dolor."
}
]}
来源:PHP Serializer which converts an object to an array that can be encoded to JSON.
你所要做的就是在输出周围包装json_encode。
有关该脚本的一些信息:
答案 9 :(得分:0)
我正在尝试使用json对象,但是没有用,但是我发现了一个问题;如果我的变量是 private
,则json_encode无法正常运行,我将其更改为 public
,则正常。
例如
不起作用;
class A{
private $var1="valuevar1";
private $var2="valuevar2";
public function tojson(){
return json_encode($this)
}
}
正在运行;
class A{
public $var1="valuevar1";
public $var2="valuevar2";
public function tojson(){
return json_encode($this)
}
}
答案 10 :(得分:-7)
我在同一个问题上花了几个小时。 我的转换对象包含许多其他我不应该接触的定义(API),所以我想出了一个解决方案,我想这可能很慢,但我用它来开发目的。
这个将任何对象转换为数组
function objToArr($o) {
$s = '<?php
class base {
public static function __set_state($array) {
return $array;
}
}
function __autoload($class) {
eval("class $class extends base {}");
}
$a = '.var_export($o,true).';
var_export($a);
';
$f = './tmp_'.uniqid().'.php';
file_put_contents($f,$s);
chmod($f,0755);
$r = eval('return '.shell_exec('php -f '.$f).';');
unlink($f);
return $r;
}
这会将任何对象转换为stdClass
class base {
public static function __set_state($array) {
return (object)$array;
}
}
function objToStd($o) {
$s = '<?php
class base {
public static function __set_state($array) {
$o = new self;
foreach($array as $k => $v) $o->$k = $v;
return $o;
}
}
function __autoload($class) {
eval("class $class extends base {}");
}
$a = '.var_export($o,true).';
var_export($a);
';
$f = './tmp_'.uniqid().'.php';
file_put_contents($f,$s);
chmod($f,0755);
$r = eval('return '.shell_exec('php -f '.$f).';');
unlink($f);
return $r;
}