PHP函数/方法中返回值的最佳实践

10
我正在逐步重构一个庞大的代码库。从长远来看,我们将会用类来开发整个系统,但同时我也利用这个机会来提高我的PHP技能并改进一些在数百个网站上使用的旧代码。

我阅读了许多关于如何最好地从自定义函数返回数据的文章,通常有两种互相矛盾的观点:一些人关注最佳技术实践,另一些人则关注易读性和呈现效果。

我想听听您对从自定义PHP函数返回的最佳实践的意见(并加以阐述)。

例如,对于下面这个基本的理论函数,我还没有确定以下哪种方法更好:

方法a.

在函数中填充返回变量,并在函数末尾返回它:

<?php
function theoreticalFunction( $var )
{
    $return = '';
    if( $something > $somethingelse ){
       $return = true;
    }else{
       $return = false;
    }
    return $return;
}
?>

方法二:

在每个端点返回:

<?php
function theoreticalFunction( $var )
{
    if( $something > $somethingelse ){
       return true;
    }else{
       return false;
    }
}
?>

一个可能的重复问题可以是使用返回true或false的函数的PHP最佳实践是什么?,但这不仅限于简单的true或false,尽管上面有我的基本示例。
我查看了PSR指南,但没有看到任何内容(但我可能错过了,所以请随时指出参考的PSR :))。
扩展原始问题:
该方法返回的方式是否取决于期望/所需的输出类型?
这种方法是否会因使用过程式或面向对象编程方法而改变?正如这个问题所显示的,面向对象带来了自己的古怪之处,以进一步扩展可能的格式/演示选项PHP返回方法的最佳实践 请尽量清楚地解释,我对您选择首选方法的原因以及在其他方法之上选择它的任何事项都感兴趣。

1
有人主张在函数中使用单一出口点(仅在结尾处使用一个return),而另一些人则主张尽早失败/返回。这只是一种基于具体情况的观点和可读性/理解性问题。几乎没有客观的技术答案。 - deceze
1
我认为这将最终成为“主观性很强”的问题,因为它取决于你想要做什么;以及程序员的经验。 - Rizier123
这很有道理,@deceze,我曾想过我是否会得到大多数“这取决于具体功能,因情况而异”的答案。也许在这里没有什么辩论?这可能解释了PSR准则中缺乏关于这个主题的信息,或者至少是我所见过的。 - JohnDevelops
这不是一件可以教条地规定的事情,毫无疑问。有些算法最好表达为A,而其他算法则更适合作为B。 - deceze
1
顺便说一句,我们甚至不要开始谈论你可怕的空格和括号使用... ;-P - deceze
显示剩余3条评论
6个回答

7
我倾向于早期返回 - 一旦知道发生了什么就离开函数。其中一种使用方式称为“守卫条款”。
其他我经常做的事情包括删除最后的else,用默认值代替:
if ($something > $somethingelse) {
   return true;
}
return false;

事实上,形如if (boolean) return true; else return false的条件语句,甚至可以进一步缩短(如果这样更清晰易懂),只需写成return ($something > $somethingelse);。将类似这样的复杂if子句从代码中提取出来,放到一个有用的命名函数中,可以帮助大大澄清代码的含义。

我认为我通过使用像你和deceze所说的那样基本的例子,并缩短我的具体示例,使用非常干净、简短的PHP来回答了自己的问题。现在显然知道每种方法有多么不同,特别是在朝着更面向对象的方法(简单、单一目的函数)努力工作时。 - JohnDevelops

4
有些人认为函数应该有一个单一的出口(仅在最后一个位置使用return),而另一些人则主张早期失败/返回。这只是一个观点问题,应根据具体情况考虑可读性和理解性。几乎没有客观的技术答案。
实际情况是,这并不是可以教条地规定的东西。有些算法用A来表达更好,而其他算法则更适合B。
在您的具体情况下,两者都不是“最佳”选择; 您的代码应编写为:
return $something > $somethingelse;

希望这可以作为一个例子,说明没有普遍适用的规则。

2
确实如此。我为你的问题措辞得当而鼓掌,并且很高兴它今天得到了普遍的好评。 - deceze
1
@deceze 一般来说,现在有一个“主要基于观点”的关闭投票原因。但是答案本身写得很好,我可以看出这可能会在未来被问到/帮助其他SO访客。正如你所说的:http://meta.stackoverflow.com/questions/293931/should-one-answer-terribly-poor-questions/293946#comment191662_293946 :) - Rizier123
@Rizier 对的,试图以身作则。如果答案是“基于观点”,那么我们不妨就这样回答它。 - deceze
2
说实话,我一开始就知道这会是更多的观点,忽略了SO通常不喜欢基于观点的问题,尽管有时候产生一些辩论会很好。我想我应该去寻找一个论坛来做这件事 :) 尽管这个演示提供了与经验丰富的开发人员良好的接触,但我真的很重视听到你们诚实友好的意见,它对我和其他人都有价值,可惜在stackoverflow上它不是一种被接受的格式 :) - JohnDevelops
1
@John,这对于评论来说有点超纲了,但我非常支持在网站上获得更多这样的问题,特别是为了对抗那些常规的代码调试问题。它只需要用恰当的措辞表达出来,就能吸引到好的回答,这是个棘手的问题。 - deceze
显示剩余3条评论

2

我知道这个问题很老,但它很有趣,就我而言,有很多事情可以说。

首先要说的是在函数或者方法中返回值没有真正的标准。

通常由你的团队决定遵循什么规则,但如果你是唯一进行重构的人,那么你可以按照自己的想法来做。

在返回值的情况下,我认为最重要的是“可读性”。有时为了让代码更易读和可维护,牺牲一点性能是值得的。接下来我将尝试用一些例子来展示其利弊。

方法A

<?php
function getTariableType($var = null)
{
    if (null === $var) {
        return 0;
    } elseif (is_string($var)) {
        return 1;
    } else {
        return -1;
    }
}
优点:
  • 明确性。每个情况都能自我解释,即使没有注释。
  • 结构性。每种情况都有一个分支,每种情况都清晰地被分隔开来,很容易为新情况添加语句。
缺点:
  • 可读性。所有这些带括号的if..else使代码难以阅读,我们必须非常注意每个部分才能理解。
  • 不必要的代码。最后一个else语句并不是必需的,如果return -1只是函数的最后一条语句,在任何else之外,代码将更容易阅读。

方法B

<?php
function isTheVariableNull($var)
{
    return (null === $var);
}

优点:

  • 可读性。代码易于阅读和理解,一眼就知道该函数正在检查变量是否为空。
  • 简洁性。只有一个语句,在这种情况下是很好和清晰的。

缺点:

  • 限制。这种表示法仅适用于非常小的函数。在更复杂的函数中使用这种表示法甚至三元运算符变得更难理解。

方法C.1

<?php
function doingSomethingIfNotNullAndPositive($var)
{
    if (null !== $var) {
        if (0 < $var) {
            //Doing something
        } else {
            return 0;
        }
    } else {
        return -1;
    }
}

优点:

  • 明确性。每个情况都是明确的,我们可以在阅读时重构函数的逻辑。

缺点:

  • 可读性。当添加许多if..else语句时,代码会变得难以阅读。代码会缩进多次,看起来很杂乱。想象一下有六个嵌套的if的代码。
  • 难以添加代码。因为逻辑似乎很复杂(即使它并不是),所以很难向函数中添加代码或逻辑。
  • 大量的逻辑。如果你有许多嵌套的if..else,可能是因为你应该创建第二个函数。例如,NetBeans IDE建议你创建另一个处理所有嵌套块逻辑的函数。函数应该是原子的,它只应该做一件事。如果它做了太多工作,有太多逻辑,那么它就很难维护和理解。创建另一个函数可能是一个好选择。

方法C.2

这种方法旨在提供C.1符号的替代方案。

<?php
function doingSomethingIfNotNullAndPositive($var)
{
    if (null === $var) {
        return -1;
    } elseif (0 >= $var) {
        return 0;
    }
    //Doing something
}

优点:

  • 易读性。这种表示法非常易读。根据给定的值,很容易理解我们将得到什么结果。
  • 明确性。与C.1一样,这种方法在每个条件分支中都是明确的。

缺点:

  • 添加逻辑困难。如果函数变得更加复杂,添加逻辑将会很困难,因为我们可能需要移动所有条件分支。

D方法

<?php
function kindOfStrlen($var)
{
    $return = -1;
    if (is_string($var)) {
        $return = strlen($var);
    }
    return $return;
}

优点:

  • 默认值。在这个结构中,我们可以看到默认值从一开始就被处理了。虽然函数中有逻辑,但如果我们没有进入任何分支,我们仍然有一个值。
  • 易于添加逻辑。如果我们需要添加一个if分支,那么很容易,并且不会改变函数的结构。

缺点:

  • 不需要的变量。在这种情况下,$return变量是不必要的,我们可以写出同样的函数而不使用它。解决方案是在结尾处返回-1,在if中返回strlen($var),这样不会影响可读性。

结论

我没有列出所有可能的符号,只列出了其中一些。我们可以考虑的是没有完美的方法,但在某些情况下,一种方法似乎比另一种更好。例如,is_null函数与B方法相结合将是很好的。

使用一种方法或另一种方法真的取决于您,重要的是选择一种逻辑,并在整个项目中保持它。


0
使用方法 b 对我来说更好,因为在方法 a 中你只写了很少的代码,但如果有很多行代码和很多返回语句,那么我可能会在某个地方使用错误的返回类型,其中 $return 被赋值给其他地方而我没有注意到。

0

我更喜欢变量b。它不仅更易读(你知道在return语句之后的所有代码都不需要考虑),而且更加安全。

如果你在剩余的代码中有一个错误,或者在设计系统时没有考虑到一组条件,那么可能会改变你的结果。当你使用return [$someVariable]退出函数时,这种情况是不可能发生的。


0
<?php
function theoreticalFunction( $var )
{
    if( $something > $somethingelse ){
       return true;
    }
    return false;
}
?>

这种方法也可以用作RETURN语句,程序光标将返回并且下一条语句不会被执行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接