Reputation: 20309
Example from the PHP documentation:
http://php.net/manual/en/function.openssl-public-encrypt.php
openssl_public_encrypt (
string $data , string &$crypted , mixed $key [, int $padding =
OPENSSL_PKCS1_PADDING ]
)
In this case it expects $crypted as a passed reference. The function works without setting up $crypted beforehand.
In a lot of example I see $crypted being initialized before calling the function.
var $crypted = '';
Is this really needed(or technically more correct) or is it fine to not set up the variable even though it is a 'pass by reference' variable?
Upvotes: 1
Views: 103
Reputation: 17720
More of a comment than an answer - but too long for a comment box. And a fascinating question that leaves me asking "why".
To answer directly:
extract
that create variables from no-where.) But I'm sure others will disagree.But this leads to the question of WHY it works like that? And I'd love to know.
First thing to note is that variables and variables passed by reference changed a lot from PHP 5 to PHP 7. An interesting read here: https://nikic.github.io/2015/05/05/Internal-value-representation-in-PHP-7-part-1.html that explains the differences.
But in both PHPs, variables are stored in the zval space with a reference counter of how many times the variable is referenced. (That doc above is the best example I've found on explaining it, but there's more in the manual)
When you extend PHP and add new functions, you get variables from the Zend API using zend_parse_parameters
. This means variables passed to the functions are also stored in the zval container and passed between the API and the extension. (Further reading - this relates to PHP5 but appears the same for PHP7).
My understanding (and I'm happy to be corrected) is explained in the four code samples:
1)
function increment($i) {
$i++;
}
increment(3);
The variable 3
is not declared (obviously), but it needs to be in the zval container for passing to the API. This shows the the calling function has the capability to generates a variable in zval container. (As it's not a real variable, I presume it "immmutable" but that's a guess.)
2)
function increment($i) {
$i++;
}
increment($y);
This errors as $y
is not declared first. Notice: Undefined variable: y in test.php
. So here it's unable to generate $y
and put in local scope.
3)
function increment($i) {
$i++;
}
$y = 0;
increment($y);
The variable is declared and put into zval container. When calling the functions, refcount will be increased so it can be passed to the API. Works as expected.
4)
function increment(&$i) {
$i++;
}
increment(3);
This errors Fatal error: Only variables can be passed by reference in test.php
. This tells us that the variable 3
is rejected by zend_parse_parameters
as it knows it's immutable, or that the calling function knows the function expects a variable by reference.
5)
function increment(&$i) {
$i++;
}
$y = 0;
increment($y);
The variable $y
is put into zval container in the current scope on the first line, and generates the reference pointer to $y
(increase refcount twice).
6)
function increment(&$i) {
$i++;
}
increment($y);
This is where it goes pear-shapes IMO: Although the variable is not declared, but $y == 1
. This means that the function must both create the variable and put into zval container in the current scope, and generate the reference pointer to $y
(increase refcount).
To do this, it must know that the function is expecting a value by reference - otherwise why is the behaviour different from 2?
And none of this answers why it's different. Just because it can create a variable (as shown in example 1), why doesn't it in example 2, but it does in example 6?
Upvotes: 1
Reputation: 37048
Although the variable will be created, I prefer to set it explicitly for number of reasons:
isset
afterwardsNot sure if any of them apply to openssl_public_encrypt
in particular, but since you get used to set variables before function calls, changing this behaviour requires more efforts and attention than it deserves.
Upvotes: 1