Пример из документации 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 это объясняет различия.
Но в обоих PHP переменные хранятся в пространстве zval со счетчиком ссылок на то, сколько раз на переменную ссылаются. (Этот документ выше — лучший пример, который я нашел при объяснении, но есть больше в руководство)
Когда вы расширяете PHP и добавляете новые функции, вы получаете переменные из Zend API, используя zend_parse_parameters
, Это означает, что переменные, передаваемые в функции, также хранятся в контейнере 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
, Это говорит нам о том, что переменная 3
отклонено zend_parse_parameters
поскольку он знает, что он неизменен, или что вызывающая функция знает, что функция ожидает переменную по ссылке.
5)
function increment(&$i) {
$i++;
}
$y = 0;
increment($y);
Переменная $y
помещается в контейнер zval в текущей области видимости в первой строке и генерирует указатель ссылки на $y
(увеличить счет в два раза).
6)
function increment(&$i) {
$i++;
}
increment($y);
Это то место, где оно имеет форму груши. ИМО: хотя переменная не объявлена, но $y == 1
, Это означает, что функция должна как создать переменную, так и поместить ее в контейнер zval в текущей области видимости, а также сгенерировать указатель ссылки на $y
(увеличить счет).
Для этого он должен знать, что функция ожидает значение по ссылке — в противном случае, почему поведение отличается от 2?
И ни один из этих ответов не объясняет, почему все по-другому. Просто потому что Можно создать переменную (как показано в примере 1), почему не в примере 2, а в примере 6?
Хотя переменная будет создана, я предпочитаю устанавливать ее явно по ряду причин:
isset
впоследствииНе уверен, если какой-либо из них относится к openssl_public_encrypt
в частности, но так как вы привыкли устанавливать переменные перед вызовами функций, изменение этого поведения требует больше усилий и внимания, чем оно того заслуживает.