PHP 里 empty((object)[])是 false 还是 true? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sagaxu
V2EX    PHP

PHP 里 empty((object)[])是 false 还是 true?

  •  1
     
  •   sagaxu 2020-07-08 15:39:57 +08:00 via Android 4509 次点击
    这是一个创建于 1930 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这么设计是否符合直觉?
    第 1 条附言    2020-07-08 21:22:42 +08:00
    如果 JSON API 定义的返回值是 map 类型,且要求不能为 null 的时,因为 PHP 到 JSON 只有[]没有{},空 map 需要写成(object)[]是常见的解决方法。然后遇到用 empty 判断 map 是不是空的代码,就歇菜了。

    不区分 map 和 list,看似很灵活,但同时也有不少坑。
    32 条回复    2020-07-09 18:03:32 +08:00
    ksaa0096329
        1
    ksaa0096329  
       2020-07-08 15:44:04 +08:00
    false
    有时间来问,早就测试出来了.
    再说了 你这种写法有什么意义.
    iamverylovely
        2
    iamverylovely  
       2020-07-08 16:10:47 +08:00
    符合啊,不然又要 emptyObject();
    zarte
        3
    zarte  
       2020-07-08 18:29:08 +08:00
    false 一定是用了那些查询回来是 obj 的 orm 了吧,哈哈。
    lovecy
        4
    lovecy  
       2020-07-08 20:22:06 +08:00
    empty,只针对
    0,空 string,空数组,false,'0',null,未定义变量
    这几种返回 true,其他都是 false
    毕竟 object 判断是比较复杂的,除非新增一个__empty 魔术方法
    jhdxr
        5
    jhdxr  
       2020-07-08 23:08:04 +08:00
    作为一个对象,判断 empty 非空,我觉得没啥不符合直觉的。大概想了想好像没啥语言会默认提供一个判断 object 为空的情况?

    JSON.parse('{}')==null
    false
    jhdxr
        6
    jhdxr  
       2020-07-08 23:10:02 +08:00
    『不区分 map 和 list,看似很灵活,但同时也有不少坑』这句话我不反对,在做 spread operator 相关的东西的时候的确就掉进去过。

    但是就你这个帖子,你混淆了 map 和 object
    sagaxu
        7
    sagaxu  
    OP
       2020-07-08 23:54:24 +08:00 via Android
    @jhdxr 因为 PHP 中想要 json_encode 之后得到{}而不是[],最简便的方式就是用 object,不管是(object)[]还是 new \stdClass 或 new class{},类型就变成了 array | object,埋下了一个坑。几层调用之后,后面的人容易忽视掉这个细节。

    某些 PHP 项目为了避免这个麻,干脆约定 JSON 中所有值为[]或{}的字段都传 null 或不包含这个字段。
    jhdxr
        8
    jhdxr  
       2020-07-09 03:27:16 +08:00
    @sagaxu 在我的理解中,json_encode 某种意义上也已经是 view 层的东西,那么有诸如某些字段应该是 map 而非 array 这种限制也应该在这一层去做掉,而非直接通过修改原始的数据去实现。

    传 null 这个方案个人认为非常不妥,两者的语义不完全相同
    DavidNineRoc
        9
    DavidNineRoc  
       2020-07-09 08:54:56 +08:00
    楼主这种只传递一个 {} 我是没看懂,为什么你的这个语义就好了.
    个人认为正确的
    // 正常
    {
    "data": {
    "id": 1,
    "name: "foo"
    }
    }

    // 空对象
    {
    "data": {
    // 同类型
    "id": null or -1,
    "name": "",
    }
    }

    // 楼主的, 这个让前端怎么判断, getAttribute 之前先 if exists ?
    {
    "data": {

    }
    }

    // 还不如直接给个 null, 前端知道不用解析了
    {
    "data": null,
    }

    不过每种方法都可以,一切最重要的是约定.
    JJstyle
        10
    JJstyle  
       2020-07-09 09:11:35 +08:00 via iPhone
    说白了 php 就是坑,{}在 json_decode 之后会变成[],没得洗,所以有时候我们对于动态结构的 json 都是直接返回字符串给前端,让他们解析
    sagaxu
        11
    sagaxu  
    OP
       2020-07-09 09:56:24 +08:00 via Android
    @DavidNineRoc
    prop 可能是 0 个也可能是几十个
    {
    prop1: value1,
    prop2: value2,
    ...
    },0 个属性,用{}是很符合预期的
    另一种方式打散成 list
    [
    {name:prop1, value:value1},
    {name:prop2, value:value2},
    ],然后由调用者自己组装成 map 或 object 使用,然后用[]表示 0 个
    @jhdxr 有时候只是转发和简单维护,比如某个中间件,对具体数据结构是不知情的,只知道一些 common 的字段,decode 后稍微改改再 encode 回来,碰到{}变[]的情况,就不能简单处理了。
    NjcyNzMzNDQ3
        12
    NjcyNzMzNDQ3  
       2020-07-09 10:18:42 +08:00
    @sagaxu
    1 、解决楼主不想返回 NULL,不用你费力 empty,另外 json 里“[],{}”不影响前端做判断

    <?php

    $linksArray = [1, 4, "0", "V", null, false, true, 'true', "N"];
    var_dump(json_encode(array_map('strval', $linksArray)));


    @JJstyle
    1 、{}在 json_decode 之后会变成 [],emm,php 默认解析 object 的
    2 、动态解析的 json 直接返回字符串,让前端判断是否是字符串或者是 JSON,这操作真是看不懂。我认为在制订 API 、数据结构时就能解决这些奇怪的问题。

    <?php

    // default object
    var_dump(json_decode('{}')); // object(stdClass)#1 (0) { }

    // array
    var_dump(json_decode('{}', true)); // array(0) { }

    最后说一点语言都有存在的道理,不要捧一个语言踩一个语言,我认为这个行为很 low
    brader
        13
    brader  
       2020-07-09 10:24:17 +08:00   1
    @JJstyle 你仔细了解过 php 的 json_encode函数了吗?看手册了吗?这句话也送给楼上的一些人。
    麻烦去看看 json_encode 的 JSON_FORCE_OBJECT 参数好吗?
    sagaxu
        14
    sagaxu  
    OP
       2020-07-09 10:26:49 +08:00 via Android
    @NjcyNzMzNDQ3 前端不仅仅是 js,还有客户端,类型不匹配解析会报错
    pinews
        15
    pinews  
       2020-07-09 10:28:48 +08:00
    楼主,说清楚你到底想怎么样? php 是弱类语言,很多时候是优势,你非要反过来把优势当劣势用,要不用===,既然是不熟悉的地方,就别贸然用==
    sagaxu
        16
    sagaxu  
    OP
       2020-07-09 10:29:01 +08:00 via Android
    @brader 两个空数组,一个要序列化成[],另一个要{},forceobject 一刀切显然是不行的
    brader
        17
    brader  
       2020-07-09 10:35:16 +08:00
    @sagaxu 完全没有问题好吗?你可以去测试
    brader
        18
    brader  
       2020-07-09 10:36:21 +08:00
    @sagaxu
    $b = '{"a":1,"b":{},"c":[]}';
    $b = json_decode($b);
    $b = json_encode($b);

    反序列化和序列化出来的字符串,一样的
    Erroad
        19
    Erroad  
       2020-07-09 10:48:33 +08:00
    @brader 你讲的道理都没错,但是人家问的是"两个空数组,一个要序列化成[],另一个要{}"
    brader
        20
    brader  
       2020-07-09 10:53:38 +08:00   1
    @Erroad 需要序列化成{}的,加 JSON_FORCE_OBJECT 参数不就好了吗?
    如果是在一个地方有[]和{}的,那在序列化前保持好数据类型不就对了?有什么问题呢
    sagaxu
        21
    sagaxu  
    OP
       2020-07-09 11:00:52 +08:00 via Android
    @brader 把 map 都 decode 成 stdClass 也是一种办法,但跟用(object)[]表示{}没什么不同
    brader
        22
    brader  
       2020-07-09 11:07:35 +08:00
    @sagaxu 你说写法问题的话,我觉得(object)[]没啥不好的,这个语意非常明确,代码可读性也好,但简洁性有待加强,在官方还不支持{}的写法之前,我们只能这么写,你想改变他,可以提议。

    你要想想,以前数组,还要写 array()呢,现在变成[],不就是有些致力改变它的人的努力吗
    JJstyle
        23
    JJstyle  
       2020-07-09 11:54:10 +08:00
    @brader 我需要的是一个对象数组,而加上参数后变成了一个对象:

    https://gist.github.com/Jaggle/9338af5321d3294d86d350fd2cad0fc9
    JJstyle
        24
    JJstyle  
       2020-07-09 12:08:16 +08:00
    @NjcyNzMzNDQ3 我们有一个 json 的配置数据,存在数据库里,首先,解析后他是一个数组,这时进行 json_decode($json, true),没问题,但是他的元素是都是 object,而 object 就应该 decode 成 object

    u1s1,我踩 php 了?我又捧了哪个语言?
    oooooooooooo
        25
    oooooooooooo  
       2020-07-09 12:15:04 +08:00
    map 和 list 不区分确实很 SB
    NjcyNzMzNDQ3
        26
    NjcyNzMzNDQ3  
       2020-07-09 12:51:51 +08:00
    @JJstyle 忘记加断行了,只是句吐槽,没有特别针对某个人
    brader
        27
    brader  
       2020-07-09 13:45:53 +08:00
    @JJstyle 不理解你的对象数组是什么意思?你写出你所谓的对象数组的 json 串吗?
    brader
        28
    brader  
       2020-07-09 13:56:55 +08:00
    @JJstyle 还有你前面说的 {}在 json_decode 之后会变成[],
    我尝试了一下,并不是这样的

    $str = '[{},{}]';
    $data = json_decode($str);
    var_dump($data);
    输出:
    array(2) {
    [0] =>
    class stdClass#153 (0) {
    }
    [1] =>
    class stdClass#154 (0) {
    }
    }

    php 版本 7.2.1
    JJstyle
        29
    JJstyle  
       2020-07-09 13:57:38 +08:00
    @brader #23 中的第一个 ouput 就是一个对象数组(自身是一个数组,它的每个元素是一个对象)
    lovecy
        30
    lovecy  
       2020-07-09 14:24:49 +08:00
    @JJstyle 你的 json_decode,第二个参数是 true 才会把{}解析成 array(),官方文档是这么写的
    ```当该参数为 TRUE 时,将返回 array 而非 object ```
    说白了你自己用的方式不对,在这里抹黑
    yc8332
        31
    yc8332  
       2020-07-09 17:49:48 +08:00
    重来没这么写过。。要空对象就用 new stdClass
    JJstyle
        32
    JJstyle  
       2020-07-09 18:03:32 +08:00
    @lovecy
    @brader
    @NjcyNzMzNDQ3

    我误怪 json_decode 这个函数了,本质上是因为 laravel 在接收参数时,默认用的 json_decode($request, true)解析参数,因此它会把{} decode 成 [],并非抹黑,只是被坑过有点恼火。

    解决办法是 1. 针对特定接口使用 json_decode($request, false)解析参数为 object,2. 动态 json 字段使用字符串传输,依然使用 json_decode($request, true)解析参数为 array 。我们选择了第二种方案。

    我的锅我的锅我的锅
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2949 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 13:37 PVG 21:37 LAX 06:37 JK 09:37
    Do have faith in what you're doing.
    ubao msn 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