Параметры ссылок PHP и значение по умолчанию null - PullRequest
12 голосов
/ 11 ноября 2008

Допустим, у нас есть подпись метода, такая как

public static function explodeDn($dn, array &$keys = null, array &$vals = null,
    $caseFold = self::ATTR_CASEFOLD_NONE)

мы можем легко вызвать метод, пропустив все параметры после $dn:

$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com');

Мы также можем вызвать метод с 3 параметрами:

$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, $v);

и с 4 параметрами:

$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, $v, 
    Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);

Но почему невозможно вызвать метод со следующей комбинацией параметров, например:

$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, null, 
    Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);
$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', null, $v);

В чем разница между передачей null в метод и использованием значения по умолчанию? Это ограничение записано в руководстве? Можно ли его обойти?

Ответы [ 6 ]

24 голосов
/ 11 ноября 2008

Это потому что вы не можете иметь ссылку на ноль.

Вы можете иметь ссылку на переменную, которая содержит ноль - это именно то, что делает значение по умолчанию. Или вы можете передать значение null в виде литерального значения - но так как вам нужен выходной параметр, здесь это невозможно.

10 голосов
/ 15 марта 2012

Хотя вы должны создать фиктивную переменную для аргументов by-ref, если вы хотите явно передать NULL, вам не нужно создавать эту переменную в отдельной строке. Вы можете использовать выражение присваивания, например, $ dummy = NULL, непосредственно в качестве аргумента функции:

function foo (&$ref = NULL) {

    if (is_null($ref)) $ref="bar";
    echo "$ref\n";        
}

foo($dummy = NULL); //this works!
5 голосов
/ 20 ноября 2010

Я только что узнал об этом сам, и я в шоке o_O!

Это то, что PHP документация говорит:

function makecoffee($type = "cappuccino")
{
    return "Making a cup of $type.\n";
}
echo makecoffee(); // returns "Making a cup of cappuccino."
echo makecoffee(null); // returns "Making a cup of ."
echo makecoffee("espresso"); // returns "Making a cup of espresso."

Я бы ожидал, что makecoffee(null) вернется "Делая чашку капучино". Один из обходных путей, который я использовал, - это проверка внутри функции, если аргумент равен нулю:

function makecoffee($type = null)
{
    if (is_null($type)){ 
       $type = "capuccino";
    }
    return "Making a cup of $type.\n";
}

Теперь makecoffee(null) возвращает "Приготовление чашки капучино".

(Я понимаю, что на самом деле это не решает вопрос, связанный с Zend, но это может быть полезно для некоторых ...)

4 голосов
/ 03 сентября 2010

@ Томалак

На самом деле, значение по умолчанию создает переменную без какой-либо ссылки. Что-то, что вы просто не можете запустить, когда что-то передаете.

Что я нашел, чтобы проиллюстрировать причины, это следующий пример (который я не проверял):

function foo (&$ref = NULL) {
  $args = func_get_args();
  echo var_export($ref, TRUE).' - '.var_export($args, TRUE);
}
$bar = NULL;
foo();     // NULL - array()
foo($bar); // NULL - array(0 => NULL)

На мой взгляд, PHP должен предлагать способ НЕ передавать определенные параметры, как при
foo($p1, , , $p4); или аналогичный синтаксис вместо передачи NULL.
Но это не так, поэтому вы должны использовать фиктивные переменные.

1 голос
/ 11 ноября 2008

Просто чтобы подтвердить, что Томалак заявлено здесь :

Следующие работы:

$k=array();
$v=null;
$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, $v, 
    Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);

Не приятно - но объяснение ясное и понятное.

0 голосов
/ 27 января 2015

Как отметил @aschmecher в комментарии к @ Ответ Щепана здесь , выполнение func($var = null) создает уведомление о строгих стандартах.

Одно решение

Вот метод, который не генерирует таких предупреждений:

<?php
error_reporting(E_ALL | E_STRICT);

function doIt(&$x = null) {
    if($x !== null) echo "x not null: $x\n";
    $x = 2;
}

function &dummyRef() {
    $dummyRef = null;
    return $dummyRef;
}

doIt(dummyRef());

doIt(dummyRef());

Объяснение

Вместо передачи переменной мы передаем результат функции, возвращающей ссылку. Второй вызов doIt(dummy()) должен проверить, что эталонное значение $dummy не сохраняется между вызовами. Это контрастирует с созданием переменной в явном виде, где нужно помнить, чтобы очистить любое накопленное значение:

$dummyRef = null;
doIt($dummyRef);
doIt($dummyRef); // second call would print 'x not null: 2'

Применение

Итак, в примере с OP это будет:

$dn = Zend_Ldap_Dn::explodeDn(
    'CN=Alice Baker,CN=Users,DC=example,DC=com',
    $k,
    dummyRef(),
    Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER
);

Дополнительные замечания

Одна вещь, которую я мог бы волновать, - создает ли этот метод утечку памяти. Следующий тест показывает, что это не так:

<?php
function doItObj(&$x = null) {
    if(gettype($x) !== "object") echo "x not null: $x\n";
    $x = 2;
}

function &dummyObjRef() {
    $dummyObjRef = new StdClass();
    return $dummyObjRef;
}

echo "memory before: " . memory_get_usage(true) .  "\n";

for($i = 0; $i < 1000000; $i++) {
    doItObj(dummyObjRef());
}

echo "memory after: " . memory_get_usage(true) . "\n";

echo "\n$i\n";

В моей системе (с использованием PHP 5.6.4) оба вызова memory_get_usage показали ~ 262 КБ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...