PHP 方法关于引用参数或显式返回值的最佳实践

Best practice for PHP methods with regard to reference parameter or explicit return value

提问人:oucil 提问时间:3/28/2014 最后编辑:Communityoucil 更新时间:2/20/2022 访问量:1013

问:

我已经使用过这两种方法很多次,但我最近想知道为什么我没有对其中一种进行标准化,或者是否有最佳实践以及其背后的原因是什么。

虽然 PHP 的返回引用页面非常清楚地说明了关于返回引用:

仅当您有正当的技术理由时才返回引用。

...在讨论参数和返回方法时,传递引用页面并不那么清晰。

请看以下两个示例:

参考返回

class foo {
    public static function bar(&$val) {
        $val++;
    }
}

$input = 0;
foo::bar($input);
echo $input;  // outputs 1

显式返回

class foo {
    public static function bar($val) {
        $val++;
        return $val;
    }
}

$input = 0;
$input = foo::bar($input);
echo $input;  // outputs 1

这两种方法执行相同的任务并返回相同的值,但它们完成它的方式略有不同。我知道这种情况(同一任务的多个解决方案)在PHP中很常见,但我的问题是......

上述两种方法中的一种是否优于另一种方法,如果是,为什么?


我应该指出,我确实看到了其他类似的问题:按引用传递与按值传递有什么区别? 但它们处理的是效果和例子,而不是为什么一个比另一个更受欢迎。


编辑:为了省去其他人阅读关于问题优点的冗长讨论的麻烦......

在考虑底层代码(无论是 PHP 还是 C 代码)中固有的开销或优化时,我希望有一些具体的东西,以及这种效果在转换为 OpCode 并放入潜在的数千个应用程序服务器的上下文后将如何转化为性能。小的优化可能会对月底的底线产生很大的影响。

我没想到会有这种不情愿,但我的猜测是,乍一看,当你考虑基本的编程要求时,并没有区别。我们的情况不同,所以我应该在前面更具体。

如果还有人愿意参与进来,我全都听进去。

php by-reference return-type 传递值

评论

0赞 deceze 3/28/2014
PHP返回或引用的可能副本?
0赞 oucil 3/28/2014
@deceze 就像我在编辑中提到的另一个问题一样,它涉及的是效果,而不是推理。我特别在寻找最佳实践和有效的推理原因。我已经阅读了每一个答案,没有一个为其中一个提供具体原因,也没有参考最佳实践。您能否相应地删除关闭请求。
0赞 oucil 3/28/2014
@deceze 拜托,伙计,这不是同一个问题,其他人也没有得到我特别寻找的答案,或者费心在这个问题上做任何工作。让我放松一下,让我得到我正在寻找的答案。
0赞 deceze 3/28/2014
我认为骗局中的答案是完全一致的。这是您对 API 设计的决定。有些方法通过引用接受和修改参数是有意义的,而另一些方法则更有意义于返回值。你认为这个解释有什么不足之处?
0赞 oucil 3/28/2014
@deceze您在参考问题中的回答只是为了方便起见,它没有提供有关预期用例、性能问题或在各种场景中选择其中之一的影响的任何参考。它在哪里说明一种方式是修改,而另一种方式是派生?这实际上只是 OP 碰巧接受的一个意见,因为它与他的问题有关。就像你说的,这是一个 API 设计的问题,但我想以更完整的方式了解它的含义。

答:

0赞 Tyrael 3/28/2014 #1

如前所述,这取决于你。 在我看来,显式返回始终是最好的方式,所以如果你在 6 个月内回到你的代码,你不会问自己这个 var 是如何递增的!$input

当代码有 10 行时,确实很容易找出它的作用,但当你在处理一个更复杂的应用程序时就不行了。

事实上,你需要在显式返回中编写更多的代码,但它的可读性要强得多,你之后的开发者将很容易理解你做了什么,这对于你的应用程序的可维护性非常重要。

评论

0赞 oucil 3/28/2014
关于易理解性,只有当你混合搭配时才是正确的,如果你把你的原则标准化为一种或另一种方式,这很容易,只有两种选择,更不用说代码提示了。我正在寻找 OOP 意义上的一组通用原则......“由你决定”很少是真的,几乎总是有一种最好的方法做某事,PHP只是让允许“由你决定”变得太容易了。不一致是代码理解的唯一真正敌人。
1赞 CommentUser 2/20/2022 #2

关于PHP中的引用,以下是一些需要注意的问题:

  • PHP 使用写入时复制来处理赋值,因此不会将$b写入不同的变量容器,直到发生使两个变量不同的更改。可能发生的一种更改类型是,对$b的引用是由另一个变量进行的,例如(为了使它成为引用,它现在必须复制$b)。在 C++ 中,引用没有自己的内存地址,并且被视为对象本身的别名(即使在某些情况下您仍然可以有悬空引用)。在 PHP 中,引用“......不像 C 指针 [指针 - 不是 C++ 引用];例如,你不能使用它们执行指针运算,它们不是实际的内存地址,等等。鉴于上述信息,我们看到在进行更改之前,复制变量不会占用额外的内存。在某些情况下,PHP 中的引用会添加到内存中。这种情况发生在 和 (不同 ) 时,因为即使 $b 从 $a 没有更改,它也需要在单独的 zval 变量容器中$b自己的引用跟踪机制,因此触发对$b的写入。$b = $a$c = &$b$b = $a$c = &$b$c = &$a

  • PHP的当前版本和旧版本之间的差异可能导致不同的处理方式:“在PHP 4中,对象被视为其他变量,因此当将它们用作函数参数或进行赋值时,它们会被复制。在 PHP 5 中,它们总是通过引用传递的。

  • 语言,无论是人类还是计算机,通常都倾向于尽可能地简化(除非复杂性的好处大于简单性):

    • 跟踪来自函数/方法的引用更改更加困难(因为如果不查看函数/方法,就无法查看哪些参数作为引用传递)。
    • 跟踪涉及基础引用的更改更加困难。
    • 核心功能有时会以不同的方式处理引用。
      • 例如:不取消设置$a,但用于取消$b与$a的关联(在本例中,$b未设置,$a保留其值)。$b = &a; unset($b);
      • 例如:array_filter() 不适用于传递的引用。
  • 意外结果:

    • 如下代码无法按预期工作:
    $array1 = array(1,2);
    $x = &$array1[1];   // Unused reference
    $array2 = $array1;  // reference now also applies to $array2 !
    $array2[1]=22;      // (changing [0] will not affect $array1)
    print_r($array1);

Produces:
Array (
    [0] => 1
    [1] => 22    // var_dump() will show the & here
)