PHP 如何将 json 转换为对象? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
RobberPhex
V2EX    PHP

PHP 如何将 json 转换为对象?

  •  
  •   RobberPhex 2017-07-25 00:56:46 +08:00 7752 次点击
    这是一个创建于 3000 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如

    { "a": "b", "c": "d", } 

    需要转化为类:

    class A { public $a; public $b; } 

    我想到的方案如下:

    1. 添加 props 属性
    class A { public $a; public $b; const props = [ 'a', 'b' ]; 

    但是这样一来,信息就比较冗余了。

    1. 动态添加属性
    class A { const props = [ 'a', 'b' ]; } 

    $a 和$b 动态添加给 this。

    但是显然,失去了 IDE、静态代码分析工具的支持。


    目前我觉得 Go 中的,json.Marshal, json.Unmarshal 还是比较方便的,但是看起来不太适合 PHP ?

    第 1 条附言    2017-07-25 10:29:31 +08:00

    不好意思,之前的例子确实太简单了。

    比如json:

    { "action": "set", "node": { "key": "/testset", "value": "setvalue", "modifiedIndex": 19, "createdIndex": 19 } } 

    要转换成类:

    <?php class Node { /** @var string */ public $key; /** @var string */ public $value; /** @var int */ public $modifiedIndex; /** @var int */ public $createdIndex; } class Response { /** @var string */ public $action; /** @var Node */ public $node; } 

    当然,stdclass和array也可以,但是我输入$response->node->,IDE不会补全啊,而且这种对静态代码分析也不友好啊。

    41 条回复    2017-07-26 16:01:11 +08:00
    akrf
        1
    akrf  
       2017-07-25 01:23:12 +08:00 via Android
    老太婆,你还记不记得有一招从天而降的掌法?
    oh
        2
    oh  
       2017-07-25 01:26:05 +08:00
    imxieke
        3
    imxieke  
       2017-07-25 01:26:50 +08:00 via Android
    没太整明白帖子意思
    不过转成数组的话可以 先将 json 转换成数组 然后用 foreach
    关注 等待大佬解答
    akrf
        4
    akrf  
       2017-07-25 01:26:58 +08:00 via Android
    @oh 别这么耿直嘛。

    言归正传,楼主试过直接 json_decode 嘛?
    akrf
        5
    akrf  
       2017-07-25 01:27:29 +08:00 via Android
    @imxieke 楼主是其他语言的程序员,正在 PHP 入门……
    RobberPhex
        6
    RobberPhex  
    OP
       2017-07-25 01:34:16 +08:00 via Android
    json_decode 是 str 到 array,这个根本不是问题的重点。

    str 到某个特定的类的转换呢? json 中的 key 对应到 object 中的属性,有存在且为原生类型、存在且是另外一个类型(即嵌套)、不存在该字段。这三种情况如何用比较少的代码来处理。
    RobberPhex
        7
    RobberPhex  
    OP
       2017-07-25 01:37:23 +08:00 via Android
    Go 中,可以通过类的属性标签来指示如何从 json 中反序列化出来。php 好像没法添加?
    feiyuanqiu
        8
    feiyuanqiu  
       2017-07-25 01:56:44 +08:00 via Android
    … json_decode 转 json 对象,默认就是转成 stdClass 对象

    至于你的要求,你这个 json 字符串又没有带类型信息,php 怎么可能知道要转成哪个类型?别什么问题都赖语言,go 在 unmarshal 的时候也要求你把要转换的类型传进去它才知道该转成什么的

    想实现你的需求,要么别用 json 用序列化;要么自己定义一个类似于 go 的 Marshalable 接口,直接继承 JsonSerializable 接口,自己实现一个通用的 unmarshal 方法,将 json 解析出来的数据初始化到具体对象
    akrf
        9
    akrf  
       2017-07-25 02:21:03 +08:00 via Android
    @RobberPhex 第一句话就错了。慢慢学习吧…
    cxbig
        10
    cxbig  
       2017-07-25 05:53:05 +08:00
    从来就不会用也不期待这样开放性的转换,一定是先定义好 class 和其中的 attribute 和 method,再把数据丢进去处理。
    torbrowserbridge
        12
    torbrowserbridge  
       2017-07-25 08:05:30 +08:00
    楼主你连主题中的第一个 json 都没写对(多了一个结尾的逗号)
    jhdxr
        13
    jhdxr  
       2017-07-25 09:01:49 +08:00
    没人发现 LZ 的 json 是 {"a":"b", "c": "d"},但类的两个属性却是$a 和$b 么。。。谁能告诉我这个转换规则是什么?
    aksoft
        14
    aksoft  
       2017-07-25 09:05:18 +08:00
    @jhdxr 高级黑
    eoo
        15
    eoo  
       2017-07-25 09:06:33 +08:00 via Android
    json_decode 不就是对象了吗?
    Tokin
        16
    Tokin  
       2017-07-25 09:11:45 +08:00
    好奇,json_decode(jsonStr)不是对象吗? json_decode(jsonStr,true)才是数组不是吗?我去试试- -
    Tokin
        17
    Tokin  
       2017-07-25 09:25:14 +08:00


    感觉没什么问题,直接 json_decode 很正确啊
    sagaxu
        18
    sagaxu  
       2017-07-25 09:39:38 +08:00 via Android
    自己实现吧,phper 一般不这么玩,他们用 stdClass 和 array
    xzem
        19
    xzem  
       2017-07-25 09:41:04 +08:00 via Android
    phper 表示这种情况不用 json_decode 自己瞎折腾啥啊。 我还觉得强类型语言的 json 反序列化难受呢。
    Tokin
        20
    Tokin  
       2017-07-25 09:42:12 +08:00
    @RobberPhex json_decode 并不是 str 到 array。。。
    sagaxu
        21
    sagaxu  
       2017-07-25 09:46:36 +08:00 via Android
    @xzem 强类型的 python,json 反序列化毫无违和感啊
    zhongkouwei
        22
    zhongkouwei  
       2017-07-25 09:48:19 +08:00
    摘一段文档:
    mixed json_decode ( string $json [, bool $assoc = false [, int $depth = 512 [, int $optiOns= 0 ]]] )
    接受一个 JSON 编码的字符串并且把它转换为 PHP 变量。
    当 assoc 参数为 TRUE 时,将返回 array 而非 object。
    xzem
        23
    xzem  
       2017-07-25 09:51:03 +08:00 via Android
    @sagaxu 哦,我上次用 c#感觉很折腾,可能不熟悉的原因
    vus520
        24
    vus520  
       2017-07-25 09:55:42 +08:00
    java 和 go 过来的,一来就开始写映射,php 里不需要啊老铁,json_decode 就够了,没错,省了 1 个小时的 coding。
    jarlyyn
        25
    jarlyyn  
       2017-07-25 10:22:05 +08:00
    一堆强答的。

    曾经也想过这个问题,由于 php 没有类型,没有 go 那样的接口,所以很难实现 go 那么爽的 json 转换。

    当然,有一些框架做过一些工作,能起到类似的作用。

    如 yii 框架 1.x 为例。

    首先 yii 实现了一个 CComponent 的基础组建。

    所以所有 yii 的类都有可以用 yii::createCpmponent 方法初始化数组为你想要的类。

    这是第一步。

    然后,Yii 的数据库和表单的基类都是 CForm

    CForm 可以制定每个字段的验证规则

    然后通过 setAttriutes 方法,将一个数组的值制定给一个 CForm 类。

    最后,我的选择呢,小项目调接口为主的还是走 go,简单多了。
    RobberPhex
        26
    RobberPhex  
    OP
       2017-07-25 10:32:34 +08:00
    @jarlyyn 但是这样对外界依赖太多啦,和 yii 绑定确实不好。

    看了下,https://github.com/AnujRNair/php-json-marshaller 是一个不错的尝试。
    gouchaoer
        27
    gouchaoer  
       2017-07-25 10:37:33 +08:00
    我个人觉得 php 的 json 操作真的是最简单的了,就用 array 搞定一切
    bombless
        28
    bombless  
       2017-07-25 10:39:55 +08:00
    v2 的 php 水平不太行,哈哈

    以前瞎逛 StackOverflow 的时候看过别人的解决方案,比较 hack,大意就是得到 stdClass 实例后 serialize() ,之后去修改那串编码,后面再 unserialize() 回来。当然这样做的前提是你已经知道要转成什么类型了。
    jarlyyn
        29
    jarlyyn  
       2017-07-25 10:47:22 +08:00
    @RobberPhex

    方法肯定有很多种。

    但为何不在重视这样的项目里直接用 go 呢-____-

    有这个需求基本就是做接口接受 json 数据吧,php 本身优势也不大啊。
    linoder
        30
    linoder  
       2017-07-25 12:00:37 +08:00
    json_decode 后需要加方法可以用 php7 Closure::call 多看看 php.net
    yzmm
        31
    yzmm  
       2017-07-25 13:22:59 +08:00
    php 的 json 库支持得不够友好,没法直接序列化一个 class 也没法直接反序列化
    Balthild
        32
    Balthild  
       2017-07-25 13:46:58 +08:00
    好多人不审题就答……
    voocel
        33
    voocel  
       2017-07-25 14:26:41 +08:00
    我来强答一波...
    voocel
        34
    voocel  
       2017-07-25 14:27:07 +08:00
    为什么叫你老太婆
    POPOEVER
        35
    POPOEVER  
       2017-07-25 14:35:24 +08:00
    类不行的,#31 说得对的,你得自己扩展,或者看看这个 https://github.com/cweiske/jsonmapper
    chahualao
        36
    chahualao  
       2017-07-25 17:16:21 +08:00
    我第一眼看标题,啊,这不 json_decode 不就完了吗? 然后楼主思路,啊?我是不是理解错了?啊,难道我学的东西有问题?啊,我要去试一下。。。。。。
    erming
        37
    erming  
       2017-07-25 17:51:52 +08:00
    @RobberPhex json_decode 是 str 到 array ? 查下手测吧,第二个参数什么意思
    junbguistar
        38
    junbguistar  
       2017-07-25 18:26:47 +08:00
    看了评论才 get 到楼主的 point
    ditel
        39
    ditel  
       2017-07-25 19:52:18 +08:00 via Android
    先转数组,再组合成想要的,再转回 json,再转成 stdclass,估计可以,自己 hack
    cnwggu
        40
    cnwggu  
       2017-07-26 13:30:45 +08:00
    同意 #35 楼,jsonmapper 可以一试
    opengg
        41
    opengg  
       2017-07-26 16:01:11 +08:00
    json 没有类型信息,瞎搞啥呀。

    需要类型的话,你改用 wsdl 吧,舒服了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3988 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 05:16 PVG 13:16 LAX 22:16 JFK 01:16
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86