这是我的场景,
我使用的是PHP和Jquery。
一个对象被编码为Json并发送到浏览器,然后用户对数据进行更改并更新,已经传递的Json字符串现在被返回到要解码的类。
如何确保在解码Json字符串时,可以使用从新Json字符串定义的新数据重新创建对象。
我是否必须重新初始化传递要在新对象中重新定义的数据,或者是否有自动获取数据的方法?
是否自动?不,没有办法将JSON字符串映射到构造函数。不过,您可以编写自己的函数,或者在对象的构造函数中进行一些检查
function jsonToClass($string, $class)
{
$className = $class;
if (is_object($class)) $className = get_class($class);
return new $className(json_decode($string));
}
然后,在对象的构造函数中:
class MyClass
{
private $prop1 = null;
public $prop2 = null;
private $set = array('prop2', 'prop1');
public function __construct(stdClass $json)
{
foreach($json as $prop => $val)
{//set properties
if (in_array($prop, $this->set)) $this->{$prop} = $val;
}
}
}
为了方便地json-ify您的对象,您甚至可以实现__toString
魔术方法,或者您必须手动调用的方法:
public function __toString()
{
$return = array();
foreach($this->set as $prop)
{
$return[$prop] = $this->{$prop};
}
//optionally - probably a bad idea, though
$return['class'] = __CLASS__;
return json_encode($return);
}
然后,当发送此类的实例时,只需执行以下操作:
return (string) $instance;
顺便说一句,你可以手动调用的方法看起来很相似,但可能更可取:
//define format constants
const FORMAT_ARRAY = 1;
const FORMAT_OBJ = 2;
const FROMAT_JSON = 3;
//some specials
const FORMAT_OBJ_REC = 4;//recursive object
public function format($format = self::FORMAT_ARRAY, array $exclude = array())
{
$return = array();
foreach($this->set as $prop)
{
if (!in_array($prop, $exclude) $return[$prop] = $this->{$prop};
}
//optionally - probably a bad idea, though
if (!in_array('class', $exclude)) $return['class'] = __CLASS__;
switch($format)
{
case self::FORMAT_ARRAY: return $return;
case self::FORMAT_OBJ: return (object) $return;
case self::FORMAT_OBJ_REC: return json_decode(json_encode($return));
case self::FORMAT_JSON: return json_encode($return);
}
}
等等。
备注
我不以JSON字符串返回类的原因很简单,因为这是服务器端信息,客户端/前端不知道发送了什么类,所以不要发送它。FORMAT_OBJ_REC
的原因很简单,因为转换为对象只转换数组,而不是递归转换:
$foo = (object) array('foo' => array('bar' => 'foobar'));
var_dump($foo->foo);
转储数组,而:
$foo = json_decode(json_encode(array('foo'=>array('bar'=> 'foobar'))));
var_dump($foo->foo);
将转储stdClass
的实例
最后,如果你正在考虑实现这个format
方法(在对它进行了更多的研究之后),我可以建议创建一个interface
、trait
或abstract class
来实现它吗?大致如下:
interface Formatable
{//horrid name, I know
const FORMAT_ARRAY = 1;
const FORMAT_OBJ = 2;
const FROMAT_JSON = 3;
const FORMAT_OBJ_REC = 4;
public function format($format = self::FORMAT_ARRAY, array $exclude = array());
}
//implement for data classes
abstract class DataModels implements Formatable
{
protected $properties = array();
public $something = null;
final public function format($format = self::FORMAT_ARRAY, array $exclude = array())
{
$return = array();
foreach($this->set as $prop)
{
if (!in_array($prop, $exclude))
{//format recursively through type-hinting!
$return[$prop] = $this->{$prop} instanceof Formatable ?
$this->{$prop}->format($format, $exclude) : $this->{$prop}
}
}
if (!in_array('class', $exclude)) $return['class'] = __CLASS__;
switch($format)
{
case self::FORMAT_ARRAY: return $return;
case self::FORMAT_OBJ: return (object) $return;
case self::FORMAT_OBJ_REC: return json_decode(json_encode($return));
case self::FORMAT_JSON: return json_encode($return);
default:
throw new InvalidArgumentException($format. ' is not a valid format type');
}
}
}
警告
这些代码都没有经过测试,我只是在这里写下了它,它很可能包含错误。