您是否应该事先设置"按引用传递"变量?



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 = '';

这真的需要吗(或者技术上更正确),或者即使变量是"通过引用"变量,也不设置变量可以吗?

与其说是一个答案,不如说是一条评论-但对于评论框来说太长了。还有一个有趣的问题,让我不禁要问"为什么"。

直接回答:

  • 不声明变量不会在任何一个版本中引起"通知",因此从技术上讲,这是不需要的
  • 因此,申报是一件优惠的事情。像亚历克斯一样,我更喜欢声明可读性和清晰度。(我也更喜欢避免像extract这样在任何地方创建变量的函数。)但我相信其他人会不同意

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


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

但在这两个PHPs中,变量都存储在zval空间中,并带有一个引用次数的引用计数器。(上面的文档是我找到的解释它的最好例子,但手册中还有更多)

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

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

1)

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

变量3没有声明(显然),但它需要在zval容器中才能传递给API。这表明调用函数能够在zval容器中生成变量。(由于它不是一个真正的变量,我认为它"不可变",但这只是猜测。)

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);

这就是梨形IMO的走向:虽然变量没有声明,但$y == 1。这意味着函数必须创建变量并放入当前作用域中的zval容器中,并生成指向$y的引用指针(增加refcount)。

要做到这一点,它必须知道函数通过引用期望一个值——否则,为什么行为与2不同?

这些都不能回答为什么它不同。仅仅因为它可以创建一个变量(如示例1所示),为什么它在示例2中不创建,而在示例6中创建?

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

  • 函数中可能使用变量从中获取数据
  • 这个变量可能没有在函数中设置,所以之后我不需要麻烦isset
  • 变量可能已经在代码的其他地方定义了,因此如果函数不更改变量,就有传递垃圾或接收垃圾的风险
  • 我忘了提到的肯定很少,所以让我们把它命名为直觉

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

最新更新