2008-11-11 15 views
9

Powiedzmy mamy metoda podpis jakPHP przez referencję parametrów i domyślne zerowej

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

możemy łatwo wywołać metodę pomijając wszystkie parametry po $dn:

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

Możemy również zadzwonić metoda z 3 parametrami:

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

z 4 parametrami:

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

Ale dlaczego jest to niemożliwe, aby wywołać metodę z następującej kombinacji parametrów, na przykład:

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

Jaka jest różnica między przechodząc null metody i opierając się na wartości domyślne? Czy to ograniczenie jest zapisane w instrukcji? Czy można go obejść?

Odpowiedz

22

To dlatego, że nie można mieć odniesienia do wartości zerowej.

Możesz mieć odniesienie do zmiennej, która zawiera wartość null - dokładnie to robi wartość domyślna. Lub możesz podać wartość null jako wartość dosłowną - ale ponieważ chcesz mieć parametr out, nie jest to możliwe tutaj.

1

Wystarczy, aby potwierdzić to, co Tomalak stwierdził here:

następujące prace:

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

nieładnie - ale wyjaśnienie jest jasne i zrozumiałe.

4

@ Tomalak

Faktycznie, wartość domyślna tworzy zmienną bez jakiegokolwiek odniesienia zaangażowanych. To jest coś, czego po prostu nie możesz zacząć, kiedy coś przekazujesz.

Co znajdę w celu zilustrowania powodów jest następujący przykład (który nie testowałem):

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) 

Moim zdaniem, PHP powinny oferować sposób, by nie przekazać pewne parametry, jak z
foo($p1, , , $p4); lub podobna składnia zamiast przekazywania NULL.
Ale tak nie jest, więc musisz używać zmiennych fikcyjnych.

+0

To interesujący pomysł na składnię ... osobiście chciałbym zobaczyć możliwość nadania nazwanych parametrów funkcji w wywołaniu, np. 'doSomething ($ var1, @ optionalParam4 = $ var2);'. –

5

Właśnie się o tym dowiedziałem i jestem w szoku o_O!

To właśnie PHP documentation mówi: "Dokonywanie filiżankę cappuccino"

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." 

Liczyłam makecoffee(null) wrócić. Jeden obejście Użyłem jest sprawdzenie wewnątrz funkcji, jeśli argument ma wartość null „Robię kubek cappuccino”

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

Teraz makecoffee(null) zwrotów

(zdaję sobie sprawę, to w rzeczywistości nie rozwiązuje Zend związanego pytanie, ale może to być przydatne dla niektórych ...)

10

Choć trzeba utworzyć zmienną manekina przez-ref argumentów, jeśli chcesz przekazuj NULL jawnie, nie musisz tworzyć tej zmiennej w osobnym wierszu. Można użyć wyrażenia przypisania jak $ manekina = null bezpośrednio jako argument funkcji:

function foo (&$ref = NULL) { 

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

foo($dummy = NULL); //this works! 
+4

To daje mi ostrzeżenia w trybie ścisłym: 'Surowe normy PHP: tylko zmienne powinny być przekazywane przez odniesienie w (snip) /test.php na linii 9' – asmecher

+0

Jeśli zmienna' $ dummy' jeszcze nie istnieje, to będzie miało wartość null, gdy przekażesz go w ten sposób: 'foo ($ dummy)'. Jeśli chcesz ponownie użyć tej zmiennej 'dummy' i chcesz mieć jedną linijkę, możesz zawsze: a) upewnić się, że nie zostanie ona zmieniona z null w twojej funkcji lub b) wykonaj to:' ($ dummy = null) i foo ($ dummy) '. –

0

Jak @aschmecher zauważył w komentarzu @Szczepan's answer here, robi func($var = null) generuje surowe normy zauważy.

Jedno rozwiązanie

Oto metoda, która nie generuje żadnych takich ostrzeżeń:

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

Objaśnienie

zamiast przechodzącą w zmiennej, mijamy w wyniku funkcji zwracającej referencję. Drugie wywołanie doIt(dummy()) polega na sprawdzeniu, czy wartość referencyjna nie występuje między wywołaniami. Kontrastuje to z tworzeniem zmienną wyraźnie, gdzie trzeba pamiętać, aby usunąć nagromadzony wartość:

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

Zastosowanie

Więc przykład OP, byłoby:

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

Dodatkowe informacje

Jedna rzecz, którą mogę się martwić s czy ta metoda powoduje przeciek pamięci. Poniższy badanie pokazuje, że tak nie jest:

<?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"; 

W moim systemie (PHP 5.6.4), zarówno wzywa do memory_get_usage pokazał ~ 262 KB.

Powiązane problemy