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 · 4190 次点击
    这是一个创建于 1627 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这么设计是否符合直觉?
    第 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   ·   实用小工具   ·   2387 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 02:25 · PVG 10:25 · LAX 18:25 · JFK 21:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.