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

多个组合逻辑判断是 if else 更合理 还是 goto 最后输出之前更合理?

  •  
  •   l1905 · 2015-09-01 10:31:27 +08:00 · 6356 次点击
    这是一个创建于 3373 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比方有如下两种例子

    第一种写法

    function a () {
        if ($is_pass_1 ) {
            if ($is_pass_2 ) {
                if ($is_pass_3 ) {
                    //...
                    //业务代码处理
                    return result;
                }
            }
        }
    }
    

    第二种写法

    function b () {
        if (!$is_pass_1 ) {
            //逻辑处理
            goto xxxxx;
        }
        if (!$is_pass_2 ) {
            //逻辑处理
            goto xxxxx;
        }
        if (!$is_pass_3 ) {
            //逻辑处理
            goto xxxxx;
        }
        //业务代码处理
    
        xxxxxx: #goto 到的位置
        // result =
        return result 
    }
    
    第 1 条附言  ·  2015-09-01 12:57:13 +08:00

    之前我可能描述的不清楚, 现在补充下

    1. $is_pass_1, $is_pass_2, $is_pass_3 等不是平级的,自然是不适用 switch

    2. 每个判断之后可能都会有部分逻辑处理

    3. if 之后同样存在 else 语句

    4. 目前遵循 同一个方法, 只有最后一个出口

    5. 业务复杂后,虽然提取了公共的方法, 但依然存在很多 判断组合

    我调整后的代码结构

    第一种

    function a() {
        if($is_pass_1) {
            //部分逻辑
            if($is_pass_2) {
                //部分逻辑
                if($is_pass_3) {
                    //...
                    //业务代码处理
                    result = 'balbalbalbal';
                } else {
                    //else 逻辑
                }
            } else {
                //else 逻辑
            }
        } else {
            //else 逻辑
        }
        return result;
    }
    
    第 2 条附言  ·  2015-09-01 13:21:19 +08:00

    调整后的第二种写法

    function b() {
        if(!$is_pass_1) {
            //逻辑处理
            goto xxxxx;
        }
        //逻辑处理
        if(!$is_pass_2) {
            //逻辑处理
            goto xxxxx;
        }
        //逻辑处理
        if(!$is_pass_3) {
            //逻辑处理
            goto xxxxx;
        }
        //逻辑处理
    
        //业务代码处理
    
        xxxxxx: #goto 到的位置
        // result =
        return result 
    }
    
    61 条回复    2015-09-03 13:41:24 +08:00
    est
        1
    est  
       2015-09-01 10:32:40 +08:00
    php 里难道没有 else if ?
    niinaranpo
        2
    niinaranpo  
       2015-09-01 10:32:49 +08:00
    为什么不用 switch
    feiyuanqiu
        3
    feiyuanqiu  
       2015-09-01 10:34:44 +08:00
    逻辑运算符哭晕在厕所...
    function a () {
    if ($is_pass_1 && $is_pass_2 && $is_pass_3 ) {

    }
    }
    luban
        4
    luban  
       2015-09-01 10:36:15 +08:00
    这 2 段代码不等价,实现功能不一样
    michaelzlies
        5
    michaelzlies  
       2015-09-01 10:36:42 +08:00   ❤️ 1
    l1905
        6
    l1905  
    OP
       2015-09-01 10:37:13 +08:00
    @est 这些不是平级 的 if else
    l1905
        7
    l1905  
    OP
       2015-09-01 10:45:03 +08:00
    @feiyuanqiu 每个判断条件后 都会有部分逻辑处理, 上面我可能写的不太清楚
    huijiewei
        8
    huijiewei  
       2015-09-01 10:52:16 +08:00
    一个很方便的准则就是

    尽早返回。。。

    业务逻辑再理一理吧。 goto 这种东西不用也罢
    poorguy
        9
    poorguy  
       2015-09-01 10:55:42 +08:00
    不清楚你具体业务,不过应该可以错误的先退出
    ```php
    function b () {
    if (!$is_pass_1 ) {
    //不成立的逻辑处理
    return;
    }
    //成立的逻辑处理
    ```
    morefreeze
        10
    morefreeze  
       2015-09-01 11:09:58 +08:00
    你可以用

    ```php
    do{
    if (!$cond1 ) break;
    if (!$cond2 ) break;
    while (0 );
    ```

    来避免掉 goto ,虽然你现在用 goto 都只是往下跳的,但你不保证之后别人修改你代码会怎么样理解这段呢
    l1905
        11
    l1905  
    OP
       2015-09-01 11:10:39 +08:00
    @huijiewei 呃呃呃。。 goto 到最后 应该就是遵循的尽早返回。没找到 goto 在目前逻辑下太不合理的地方
    l1905
        12
    l1905  
    OP
       2015-09-01 11:14:30 +08:00
    @poorguy 目前遵循的是复杂逻辑下只有一个出口
    otakustay
        13
    otakustay  
       2015-09-01 11:17:33 +08:00
    公用逻辑抽成另一个函数在各分支里调用就行,别用 goto
    qian19876025
        14
    qian19876025  
       2015-09-01 11:19:43 +08:00
    合适就行 为嘛一定要与趋势作对
    alphonsez
        15
    alphonsez  
       2015-09-01 11:26:11 +08:00
    goto 挺好的,尤其 C 错误处理的时候。
    ether
        16
    ether  
       2015-09-01 11:50:01 +08:00
    function a () {
    xxxxxx: #goto 到的位置
    // result =
    return result

    }

    function b () {
    if (!$is_pass_1 ) {
    //逻辑处理
    return a ();
    }
    if (!$is_pass_2 ) {
    //逻辑处理
    return a ();
    }
    if (!$is_pass_3 ) {
    //逻辑处理
    return a ();
    }
    //业务代码处理

    xxxxxx: #goto 到的位置
    return a ();
    }
    ibremn
        17
    ibremn  
       2015-09-01 11:52:12 +08:00
    举个 C 的例子吧。。
    下面的函数是把图片数据解压成 iOS 可以直接显示的 Bitmap 。。。

    第一种是遵循了"尽早返回"的原则。。。


    第二种是用了 goto 。。。


    在某些情况下,适当地用 goto 还是不错的,只要注意别出现 goto fail; goto fail; 这种 bug 就好蛤蛤蛤。。。
    pathletboy
        18
    pathletboy  
       2015-09-01 11:54:47 +08:00
    可以用 do while (0 );就别用 goto 了。
    flowfire
        19
    flowfire  
       2015-09-01 12:16:32 +08:00
    @pathletboy do while (0 ) 什么鬼
    ljbha007
        20
    ljbha007  
       2015-09-01 12:21:44 +08:00
    switch case 就是为这种情况准备的啊
    FrankFang128
        21
    FrankFang128  
       2015-09-01 12:24:26 +08:00
    你应该优化逻辑,不要出现这么多 if
    hitmanx
        22
    hitmanx  
       2015-09-01 12:24:29 +08:00   ❤️ 1
    想起了 Dijkstra 大神的那篇可能是最著名的文章<Go To Statement Considered Harmful>
    zacard
        23
    zacard  
       2015-09-01 12:53:13 +08:00
    优化逻辑,优先返回。
    kobe1941
        24
    kobe1941  
       2015-09-01 13:10:38 +08:00
    从开始学编程,所有的人包括老师和书籍都不让用 goto
    msg7086
        25
    msg7086  
       2015-09-01 13:13:58 +08:00
    @flowfire do while 0 给你机会用 break 。

    另外 Ruby 里推荐的方式是用 throw/catch 来解决。 C++/Java/PHP 的话也可以考虑用这种方法,比较干净。
    当然最好的方法肯定是拆函数,只有实在不适合拆函数的时候才考虑 goto 。
    narcotics
        26
    narcotics  
       2015-09-01 13:37:43 +08:00
    @msg7086 利用异常机制表达逻辑或许不是个好主意?
    akagi
        27
    akagi  
       2015-09-01 13:48:29 +08:00
    个人觉得可以试试表驱动?
    21grams
        28
    21grams  
       2015-09-01 14:01:02 +08:00
    goto 也可以适当的用一下,怕啥,不就是只恐龙嘛。
    msg7086
        29
    msg7086  
       2015-09-01 14:12:23 +08:00
    @narcotics Ruby 里的异常是 raise/rescue 。 throw/catch 就是用来抛球接球的。

    另外其实这种结构也算是异常。
    undef404
        30
    undef404  
       2015-09-01 14:30:31 +08:00
    @msg7086

    c++里面不推荐用异常来做逻辑控制
    l1905
        31
    l1905  
    OP
       2015-09-01 15:06:30 +08:00
    @kobe1941 我也"从开始学编程,所有的人包括老师和书籍都不让用 goto" ,但遇到具体业务逻辑的用它的时候, 却没想到强有力不用它的理由,或者说是列不出用 goto 有哪些不能容忍的缺点
    hitmanx
        32
    hitmanx  
       2015-09-01 15:13:38 +08:00   ❤️ 1
    @l1905 如果功能简单的话确实没什么。不过假如未来这个函数的功能随着迭代更新变得越来越长,越来越复杂,加之如果后续维护的人并不是当初编写者时,就很容易出各种各样的问题,因为 goto 语句破坏了结构性。即使你现在很清楚你在干什么,也不保证后续模仿你的风格继续增加 goto 语句的人也像你这样清晰,一点小看法。
    iosx
        33
    iosx  
       2015-09-01 16:04:50 +08:00
    我觉的这个逻辑用 goto 处理很好啊,代码更简洁、更易读。 linux 内核里有很多 goto 啊,尤其是逻辑块多,函数返回前还需要一些处理时,用 goto 很方便。
    computeramber
        34
    computeramber  
       2015-09-01 16:26:32 +08:00
    测试 crawl = =!
    cxbig
        35
    cxbig  
       2015-09-01 20:31:20 +08:00
    twi3325831
        36
    twi3325831  
       2015-09-01 21:40:53 +08:00
    楼主试过这种写法没

    function b () {
    do {
    if (!$is_pass_1 ) {
    //逻辑处理
    break;
    }
    //逻辑处理
    if (!$is_pass_2 ) {
    //逻辑处理
    break;
    }
    //逻辑处理
    if (!$is_pass_3 ) {
    //逻辑处理
    break;
    }
    //逻辑处理

    //业务代码处理
    } while (0 );

    // 错误处理
    // result =
    return result;
    }
    dorentus
        37
    dorentus  
       2015-09-01 22:13:30 +08:00
    说句题外话, Swift 2 为了支持尽早返回,提供了 guard 关键字来尽早返回,然后提供了 defer 关键字来解决返回导致的无法集中释放资源的问题。
    asj
        38
    asj  
       2015-09-01 22:14:50 +08:00 via iPad
    有些时候,看起来似乎今天一个程序员为软件写了 10 行代码,
    其实他写了-1000 行代码
    2015813
        39
    2015813  
       2015-09-01 22:47:58 +08:00 via Android
    大师云:果断 if ,抛弃 goto ,它会让你晕头转向。
    raincious
        40
    raincious  
       2015-09-01 23:07:07 +08:00
    看了楼主的 Append 之后再看原来的,觉得一二两种方案的区别基本上就是第二种会被打更惨而已……

    重构成这样应该就好多了:
    https://gist.github.com/raincious/c2845e414d62832db861
    cpper
        41
    cpper  
       2015-09-01 23:23:01 +08:00   ❤️ 1
    对于 if else 这种判断的,请进行读表形式处理。代码大全有类似介绍
    flowfire
        42
    flowfire  
       2015-09-02 03:17:03 +08:00
    @msg7086 不是应该是 do while 1 么、、、
    msg7086
        43
    msg7086  
       2015-09-02 05:39:04 +08:00
    @flowfire do while 1 就变成死循环了。
    vibbow
        44
    vibbow  
       2015-09-02 06:14:24 +08:00
    try
    {
    if ( ! aaaa )
    {
    throw new Exception ('aaa');
    }


    if ( ! bbb )
    {
    throw new Exception ('bbb');
    }
    }
    catch (Exception $e )
    {

    }
    flowfire
        45
    flowfire  
       2015-09-02 06:57:24 +08:00
    @msg7086
    do while 0
    就是只执行一次没什么卵用
    do while 1
    就是无限循环知道满足条件用 break 跳出。。
    有哪里不对么。。
    zhczhy
        46
    zhczhy  
       2015-09-02 08:21:28 +08:00
    允许用 goto 就 goto ,不允许时大部分情况下都可以 do { ... } while (0 )
    V2 上还是得多一些这样的纯技术讨论帖
    bdnet
        47
    bdnet  
       2015-09-02 08:27:02 +08:00
    有个叫 switch case

    更好的方式可以用字典,如果所用编程语言支持委托的话。

    goto 很容易造成死循环
    msg7086
        48
    msg7086  
       2015-09-02 08:27:57 +08:00
    @flowfire 你自己好好动脑筋想想吧……不想多吐槽了。
    romisanic
        49
    romisanic  
       2015-09-02 09:09:54 +08:00
    @ibremn
    不过不管公司要求还是自己写代码,还是尽量避免在一个方法中有过多的 return 。。。
    mcfog
        50
    mcfog  
       2015-09-02 09:22:02 +08:00
    别说 goto 了,我连 else 都不想看到,尤其是一眼看不完的()里的条件或超过 3 行的{}里的代码。战术上提前 return ,抽函数,查表什么的方法有的是,战略上说穿了就是自己其实压根没想清楚就在写代码了,自然写的一手好面条
    Mysdes
        51
    Mysdes  
       2015-09-02 09:36:29 +08:00
    在我还是个程序猿的时候,老师千叮咛万嘱咐,如果没人把刀架你脖子上,能别 goto 就别 goto ,哈哈哈
    lizhiqing1996
        52
    lizhiqing1996  
       2015-09-02 09:39:06 +08:00   ❤️ 1
    @flowfire do while 0 只执行一次,满足一定条件可以退出 while 代码块,从而实现了 goto 的功能。如果一直不退出 while 代码块,则 while 代码块里的语句只会执行一次,效果就和没用 while 一样,不会影响代码运行


    @msg7086 不知道我说得对不
    lizhiqing1996
        53
    lizhiqing1996  
       2015-09-02 09:41:06 +08:00
    我怎么看都感觉你的两串代码实现的是不一样的功能,不管是修改前或修改后...
    mornlight
        54
    mornlight  
       2015-09-02 09:42:52 +08:00
    @romisanic 这个很奇怪,许多地方是推荐多用 return 少用嵌套 if else 来明确表示方法结束和返回值,代码可读性更高。
    myv2ex
        55
    myv2ex  
       2015-09-02 10:30:27 +08:00
    尝试利用面向对象的思想, 3 个条件非平级,则必定存在引用包含关系,那么可通过定义基本模型关系,再通过接口注入模型对象到处理模型的操作对象,操作对象中根据业务逻辑定义处理各模型的不同逻辑完成继承关系,通过覆写操作取代过程化的代码处理机制,后期随着业务模型对象的增加,也仅仅是完善模型接口定义及方法而已,对今后代码发展具有积极作用。
    WordCount
        56
    WordCount  
       2015-09-02 11:06:34 +08:00 via Android
    @akagi +1 这才是正解
    soundofu
        57
    soundofu  
       2015-09-02 13:51:40 +08:00
    LZ 的第二种写法作为错误处理的时候也未尝不可,
    实际使用中,我采用的更接近 @ibremn 所说的尽早 renturn 。
    skydiver
        58
    skydiver  
       2015-09-02 13:59:00 +08:00
    @myv2ex Java 写多了吧兄弟……
    Banio
        59
    Banio  
       2015-09-02 14:04:48 +08:00
    当年学 C 语言的时候 说不推荐用 goto 。。。然后一直我就没用过
    ffffwh
        60
    ffffwh  
       2015-09-02 15:30:26 +08:00
    有限状态自动机
    zonghua
        61
    zonghua  
       2015-09-03 13:41:24 +08:00
    javascript 没有 goto,好像也不建议用 switch
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5578 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 07:46 · PVG 15:46 · LAX 23:46 · JFK 02:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.