你应该事先设置一个 'pass by reference' 变量吗?

Are you supposed to set up a 'pass by reference' variable beforehand?

PHP 文档中的示例:

http://php.net/manual/en/function.openssl-public-encrypt.php

openssl_public_encrypt ( 
    string $data , string &$crypted , mixed $key [, int $padding =         
    OPENSSL_PKCS1_PADDING ] 
)

在这种情况下,它期望 $crypted 作为传递的引用。该函数无需事先设置 $crypted 即可运行。

在很多示例中,我看到 $crypted 在调用函数之前被初始化。

var $crypted = '';

这真的需要(或技术上更正确)还是不设置变量是否可以,即使它是一个 'pass by reference' 变量?

虽然会创建变量,但我更喜欢显式设置它,原因有很多:

  • 函数中可能会使用该变量从中获取数据
  • 变量可能没有在函数中设置,所以我不需要再为isset操心
  • 变量可能已在代码的其他地方定义,因此如果函数不更改变量,则存在传递垃圾或接收垃圾的风险
  • 肯定还有几个忘记说了,就说直觉吧

不确定它们是否特别适用于 openssl_public_encrypt,但由于您习惯于在函数调用之前设置变量,因此更改此行为需要付出更多的努力和关注。

更多的是评论而不是答案 - 但对于评论框来说太长了。还有一个引人入胜的问题让我问 "why"。

直接回答:

  • 不声明变量不会在任一版本中导致 "NOTICE" - 因此从技术上讲,这不是必需的。
  • 因此申报是一件优先的事情。像 一样,为了可读性和清晰度,我更喜欢声明。 (我也更喜欢避免像 extract 这样从 no-where 创建变量的函数。)但我相信其他人会不同意。

但这引出了一个问题,为什么它会这样工作?我很想知道。


首先要注意的是,变量和通过引用传递的变量从 PHP 5 到 PHP 7 发生了很大变化。这里有一个有趣的读物:https://nikic.github.io/2015/05/05/Internal-value-representation-in-PHP-7-part-1.html 解释了差异。

但是在这两个 PHP 中,变量都存储在 zval space 中,并带有一个引用计数器,该计数器表示变量被引用了多少次。 (上面的文档是我在解释它时发现的最好的例子,但 manual 中还有更多内容)

当您扩展 PHP 并添加新函数时,您可以使用 zend_parse_parameters 从 Zend API 获取变量。这意味着传递给函数的变量也存储在 zval 容器中并在 API 和扩展之间传递。 (Further reading - 这与 PHP5 有关,但与 PHP7 相同)。

我的理解(我很高兴得到纠正)在四个代码示例中得到解释:

1)

function increment($i) {
    $i++;
}

increment(3);

变量 3 没有声明(很明显),但它需要在 zval 容器中才能传递给 API。这表明 调用函数能够在 zval 容器 中生成变量。 (因为它不是真正的变量,所以我假设它 "immmutable" 但这是一个猜测。)

2)

function increment($i) {
    $i++;
}

increment($y);

这个错误是因为 $y 没有首先声明。 Notice: Undefined variable: y in test.php。所以在这里它无法生成 $y 并放入本地范围。

3)

function increment($i) {
    $i++;
}

$y = 0;
increment($y);

变量已声明并放入 zval 容器中。调用函数时,refcount 会增加,因此可以将其传递给 API。按预期工作。

4)

function increment(&$i) {
    $i++;
}

increment(3);

这个错误 Fatal error: Only variables can be passed by reference in test.php。这告诉我们变量 3zend_parse_parameters 拒绝,因为它知道它是不可变的,或者调用函数知道函数需要一个引用变量。

5)

function increment(&$i) {
    $i++;
}

$y = 0;
increment($y);

第一行将变量$y放入当前作用域的zval容器中,并生成指向$y的引用指针(增加refcount两次)

6)

function increment(&$i) {
    $i++;
}

increment($y);

这就是它的去处pear-shapes IMO:虽然变量没有声明,但是$y == 1。这意味着该函数必须在当前范围内创建变量并放入 zval 容器,并生成指向 $y 的引用指针(增加 refcount)。

为此,它必须知道该函数需要一个引用值 - 否则为什么行为与 2 不同?

和 none 这回答了为什么它是不同的。就因为它可以创建一个变量(如示例1所示),为什么示例2不可以,而示例6可以呢?