假设我有一个带有'name'和'password'属性的User类,以及一个'save'方法.当通过json_encode将此类的对象序列化为JSON时,该方法被正确跳过,我最终得到类似{'name':'testName','password':'testPassword'}的内容.
但是,当通过json_decode反序列化时,我最终得到一个StdClass对象而不是User对象,这是有道理的,但这意味着该对象缺少"保存"方法.有没有办法将结果对象作为用户进行转换,或者为json_decode提供一些关于我期望的对象类型的提示?
老问题,但也许有人会觉得这很有用.
我已经创建了一个带有静态函数的抽象类,您可以在对象上继承这些函数,以便将任何JSON反序列化为继承类实例.
abstract class JsonDeserializer { /** * @param string|array $json * @return $this */ public static function Deserialize($json) { $className = get_called_class(); $classInstance = new $className(); if (is_string($json)) $json = json_decode($json); foreach ($json as $key => $value) { if (!property_exists($classInstance, $key)) continue; $classInstance->{$key} = $value; } return $classInstance; } /** * @param string $json * @return $this[] */ public static function DeserializeArray($json) { $json = json_decode($json); $items = []; foreach ($json as $item) $items[] = self::Deserialize($item); return $items; } }
您可以通过在具有JSON将具有的值的类上继承它来使用它:
class MyObject extends JsonDeserializer { /** @var string */ public $property1; /** @var string */ public $property2; /** @var string */ public $property3; /** @var array */ public $array1; }
用法示例:
$objectInstance = new MyObject(); $objectInstance->property1 = 'Value 1'; $objectInstance->property2 = 'Value 2'; $objectInstance->property3 = 'Value 3'; $objectInstance->array1 = ['Key 1' => 'Value 1', 'Key 2' => 'Value 2']; $jsonSerialized = json_encode($objectInstance); $deserializedInstance = MyObject::Deserialize($jsonSerialized);
::DeserializeArray
如果您的JSON包含目标对象的数组,则可以使用该方法.
这是一个可运行的样本.
我认为处理这个的最好方法是通过构造函数,直接或通过工厂:
class User { public $username; public $nestedObj; //another class that has a constructor for handling json ... // This could be make private if the factories below are used exclusively // and then make more sane constructors like: // __construct($username, $password) public function __construct($mixed) { if (is_object($mixed)) { if (isset($mixed->username)) $this->username = $mixed->username; if (isset($mixed->nestedObj) && is_object($mixed->nestedObj)) $this->nestedObj = new NestedObject($mixed->nestedObj); ... } else if (is_array($mixed)) { if (isset($mixed['username'])) $this->username = $mixed['username']; if (isset($mixed['nestedObj']) && is_array($mixed['nestedObj'])) $this->nestedObj = new NestedObj($mixed['nestedObj']); ... } } ... public static fromJSON_by_obj($json) { return new self(json_decode($json)); } public static fromJSON_by_ary($json) { return new self(json_decode($json, TRUE)); } }
简答:不(不是我知道*)
答案很长:json_encode只会序列化公共变量.正如您在JSON规范中看到的那样,没有"函数"数据类型.这些都是您的方法未序列化到JSON对象的原因.
Ryan Graham是对的 - 重新创建这些对象作为非stdClass实例的唯一方法是在反序列化后重新创建它们.
例
firstName = $firstName; $this->lastName = $lastName; } public static function createFromJson( $jsonString ) { $object = json_decode( $jsonString ); return new self( $object->firstName, $object->lastName ); } public function getName() { return $this->firstName . ' ' . $this->lastName; } } $p = new Person( 'Peter', 'Bailey' ); $jsonPerson = json_encode( $p ); $reconstructedPerson = Person::createFromJson( $jsonPerson ); echo $reconstructedPerson->getName();
或者,除非您确实需要将数据作为JSON,否则您可以使用常规序列化并利用__sleep()和__wakeup()挂钩来实现其他自定义.
*
在我之前的一个问题中,有人建议您可以实现一些SPL接口来自定义json_encode()的输入/输出,但我的测试显示那些是疯狂的追逐.