V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
RobberPhex
V2EX  ›  PHP

PHP 如何将 json 转换为对象?

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

    比如

    {
      "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   ·   实用小工具   ·   2818 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 14:02 · PVG 22:02 · LAX 06:02 · JFK 09:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.