Php 在具有神奇属性的类上进行json_编码
我正在尝试使用Php 在具有神奇属性的类上进行json_编码,php,json,Php,Json,我正在尝试使用\u get和\u set对所有具有魔法属性的对象数组进行json\u编码json_encode完全忽略这些属性,导致空对象数组(所有正常属性都是private或protected) 那么,想象一下这个类: class Foo { public function __get($sProperty) { if ($sProperty == 'foo') { return 'bar!'; }
\u get
和\u set
对所有具有魔法属性的对象数组进行json\u编码json_encode
完全忽略这些属性,导致空对象数组(所有正常属性都是private
或protected
)
那么,想象一下这个类:
class Foo
{
public function __get($sProperty)
{
if ($sProperty == 'foo')
{
return 'bar!';
}
return null;
}
}
$object = new Foo();
echo $object->foo; // echoes "foo"
echo $object->bar; // warning
echo json_encode($object); // "{}"
我已经尝试为类实现了IteratorAggregate
和Serializable
,但是json_encode
仍然没有看到我的神奇属性。由于我试图对这些对象的数组进行编码,因此类上的AsJSON()
-方法也无法工作
更新这个问题似乎很容易被误解。我怎样才能知道存在哪些“神奇属性”<代码>迭代器聚合
不起作用
顺便说一句:最重要的是“动态实体”。魔法属性是否真的存在是关于语义的争论。这是正确的行为
JSON只能包含数据而不能包含方法-它是独立于语言的,因此编码对象方法没有意义。您的评论: 我问的是魔法属性,而不是方法维加德·拉森1分钟前 没有魔法属性这样的东西。 您现在拥有的只是一个神奇的方法,当您尝试访问不可见的属性时,会调用该方法 再说一遍 $obj->foo不存在 神奇方法的实现方式与PHP无关,它无法神奇地知道您正在使用神奇方法“神奇地”使其看起来像是有
$obj->foo
如果属性不存在,则在对其进行json\u编码时将不会将其放入对象中
此外,即使json\u encode
知道\u get
处于活动状态,它也不知道使用什么值来调用它。它怎么知道您的属性
$object = new Foo();
echo $object->foo; // how do you know to access foo and not oof?
// how do you expect json_encode to know to access foo?
神奇的方法是语法上的糖分,当你使用它们时,它们大多会回击。这就是一个例子
echo json_encode($object); // "{}"
当然,它是空的,$object没有公共属性,只有一个神奇的方法和随后的语法糖(变酸)我会在对象上创建一个方法来返回内部数组
class Foo
{
private $prop = array();
public function __get($sProperty)
{
return $this->prop[$sProperty];
}
public function __set($sProperty, $value)
{
$this->prop[$sProperty] = $value;
}
public function getJson(){
return json_encode($this->prop);
}
}
$f = new Foo();
$f->foo = 'bar';
$json = $f->getJson();
json_encode()不会向对象“询问”任何接口。它通过调用obj->get\u properties()直接获取表示对象属性的哈希表指针。然后它在这个哈希表上进行迭代(同样是直接的,没有使用诸如Traversable、Iterator等接口),并处理标记为public的元素。请参见ext/json/json.c中的static void json\u encode\u array()
这使得json_encode()的结果中不可能显示属性,但不能作为$obj->propname进行访问
编辑:我没有对它进行过太多的测试,忘记了“高性能”,但你可能想从它开始
interface EncoderData {
public function getData();
}
function json_encode_ex_as_array(array $v) {
for($i=0; $i<count($v); $i++) {
if ( !isset($v[$i]) ) {
return false;
}
}
return true;
}
define('JSON_ENCODE_EX_SCALAR', 0);
define('JSON_ENCODE_EX_ARRAY', 1);
define('JSON_ENCODE_EX_OBJECT', 2);
define('JSON_ENCODE_EX_EncoderDataObject', 3);
function json_encode_ex($v) {
if ( is_object($v) ) {
$type = is_a($v, 'EncoderData') ? JSON_ENCODE_EX_EncoderDataObject : JSON_ENCODE_EX_OBJECT;
}
else if ( is_array($v) ) {
$type = json_encode_ex_as_array($v) ? JSON_ENCODE_EX_ARRAY : JSON_ENCODE_EX_OBJECT;
}
else {
$type = JSON_ENCODE_EX_SCALAR;
}
switch($type) {
case JSON_ENCODE_EX_ARRAY: // array [...]
foreach($v as $value) {
$rv[] = json_encode_ex($value);
}
$rv = '[' . join(',', $rv) . ']';
break;
case JSON_ENCODE_EX_OBJECT: // object { .... }
$rv = array();
foreach($v as $key=>$value) {
$rv[] = json_encode((string)$key) . ':' . json_encode_ex($value);
}
$rv = '{' . join(',', $rv) .'}';
break;
case JSON_ENCODE_EX_EncoderDataObject:
$rv = json_encode_ex($v->getData());
break;
default:
$rv = json_encode($v);
}
return $rv;
}
class Foo implements EncoderData {
protected $name;
protected $child;
public function __construct($name, $child) {
$this->name = $name;
$this->child = $child;
}
public function getData() {
return array('foo'=>'bar!', 'name'=>$this->name, 'child'=>$this->child);
}
}
$data = array();
for($i=0; $i<10; $i++) {
$root = null;
foreach( range('a','d') as $name ) {
$root = new Foo($name, $root);
}
$data[] = 'iteration '.$i;
$data[] = $root;
$root = new StdClass;
$root->i = $i;
$data[] = $root;
}
$json = json_encode_ex($data);
echo $json, "\n\n\n";
$data = json_decode($json);
var_dump($data);
这是一个非常古老的线程,但为了不混淆其他对如何使用魔术方法在PHP中获取/设置属性以及如何影响JSON编码感兴趣的人,我的理解如下
在类中包含uuu get和uuu set方法可以为您提供一个接口来处理给定类的动态命名属性。大多数人定义了一个内部关联数组来执行内务管理
您的foo/bar示例没有出现在JSON编码中的原因是您只是创建了一个返回值的关联。它没有将对象本身的属性设置为该值
如果您做了如下操作:
公共函数集($name,$value){
$this->data[$name]=$value;
}
如果你打电话:
$foo=新对象类;
$foo->set('foo','bar')
现在在数组$data['foo']='bar'中有一个元素
如果对对象进行json_编码,则表示该关系
json_encode不编码方法,只编码属性。这是没有办法的。对于您的代码,与magic uuu get相当的功能是在构造函数中包含对set的调用,即“硬连线”名为“foo”的属性的值
归根结底,我不知道你在争取什么细节,因为你没有提供太多的细节。但是,对对象或数组进行json_编码只会给出可用属性的列表。如果你必须通过一个解释函数,并且以某种方式依赖于它,那是一个不同的问题,不幸的是我没有答案
我希望这会有所帮助,即使它是降级线程的一部分,讽刺的是,IMO中包含了解决方案。我发现以下方法对我创建具有动态属性的类并使用json_encode输出它们很有效。也许这有助于其他人
PHP5.4有一个名为JsonSerializable
的接口。它有一个方法,jsonSerialize
,它将返回要编码的数据。通过实现它,这个问题很容易解决。没有魔法属性,只有当您尝试访问未声明的属性时调用的魔法方法。当您尝试对这些对象的数组进行json\u编码时会发生什么json\u encode
不知道调用getJson()
。问题中也提到了这一点。其想法不是使用json\u编码
。。。。而是调用对象上的getJSON。查看类后的exmaple,正如Chacha102所说,您使用我添加到类中的getJSON方法,这样就知道存在哪些属性,因为它可以访问类内部。我有一个这些对象的数组。在数组中的每个对象上调用json\u encode
并不是解决这个问题的干净方法。好吧,以您现有的结构,这似乎是唯一的方法
$obj = new StdClass;
$obj->x = new StdClass;
$obj->x->y = $obj;
echo json_encode($obj); // warning: recursion detected...
echo json_encode_ex($obj); // this one runs until it hits the memory limit