Najlepszy sposób na nadanie zmiennej domyślnej wartości (symulacja Perl ||, || =)

135

Uwielbiam robić tego typu rzeczy w Perlu: $foo = $bar || $bazprzypisanie $bazdo $foojeżeli $barjest pusta lub nieokreślona. Trzeba również $foo ||= $bletchktóry przypisze tylko $bletchna $foorazie $foonie jest zdefiniowana lub pusty.

Operator trójskładnikowy w tej sytuacji jest żmudny i męczący. Z pewnością w PHP dostępna jest prosta, elegancka metoda?

A może jedyną odpowiedzią jest funkcja niestandardowa, która używa isset ()?

Tom Auger
źródło
1
Przy okazji, operatory Perla z żądaną funkcjonalnością są //i //=istnieją od wersji Perl 5.0.0. Oryginał ||i ||=test pod kątem wartości logicznej, a nie zdefiniowania.
Palec
@Palec, dlaczego 4-letnie pytanie z 29 głosami za pozytywnymi miałoby zostać zidentyfikowane jako duplikat jednorocznego pytania z 6 pozytywnymi odpowiedziami (które samo zostało oznaczone jako duplikat innego pytania?) Myślę, że zachowanie tego jest wielką wartością pytanie, ponieważ tytuł jest bardziej ogólny (nie odnosi się do odpowiedzi, np .: isset ()).
Tom Auger
Są wyraźnymi i dokładnymi duplikatami. Przyznaję, że nie myślałem zbyt wiele o tym, który z nich powinien być oryginalny, byłem w środku czegoś innego, a celem było połączenie między nimi. Wycofuję moje VTC.
Palec
Dokładny duplikat, oznaczony (błędnie IMO) jako duplikat innego pytania: skrót PHP dla isset ()?
Palec

Odpowiedzi:

133

W PHP 7 wreszcie mamy sposób, aby zrobić to elegancko. Nazywa się to operatorem koalescencji zerowej . Możesz go używać w ten sposób:

$name = $_GET['name'] ?? 'john doe';

Jest to równoważne z

$name = isset($_GET['name']) ? $_GET['name']:'john doe';
jpschroeder
źródło
15
Twierdzę, że operator statku kosmicznego też ma zasługi.
Mariano,
3
Myślałem, że Mariano szarpie nas za nogi, ale nie, to rzecz <=>i całkiem dokładna!
HPWD,
1
Należy zauważyć, że operator łączenia wartości null zachowuje się inaczej niż operator warunkowy, ponieważ jest specyficzny dla nullwartości. Na przykład, jeśli $_GET['name']jest ustawiony na pusty ciąg, pierwsza linia zwróci pusty ciąg, ale możemy zwrócić „john doe” za pomocą $_GET['name'] ? $_GET['name'] : 'john doe'.
VPhantom
212

PHP 5.3 ma ?:operator skrótu :

$foo = $bar ?: $baz;

Który przypisuje, $barjeśli nie jest to pusta wartość (nie wiem, jak różniłoby się to w PHP od Perla), w przeciwnym razie $bazi jest taki sam jak w Perlu i starszych wersjach PHP:

$foo = $bar ? $bar : $baz;

Ale PHP nie ma do tego celu złożonego operatora przypisania (to znaczy nie ma odpowiednika Perla ||=).

Ponadto PHP będzie hałasować, jeśli $barnie jest ustawione, chyba że wyłączysz powiadomienia. Istnieje również różnica semantyczna między isset()i empty(). Pierwsza zwraca false, jeśli zmienna nie istnieje lub jest ustawiona na NULL. Te ostatnie Zwraca true, jeśli nie istnieje, lub jest ustawiony na 0, '', falselub NULL.

BoltClock
źródło
2
+1 za wprowadzenie mnie do kolejnej wspaniałej funkcji 5.3, której brakuje na moich serwerach RHEL5 / PHP5.1.2.
Michael Berkowski
Chyba masz na myśli The first returnszamiast The secondw przedostatnim zdaniu.
Toto
21
Zauważ, że jeśli twoja zmienna jest niezdefiniowana, PHP wyśle ​​o niej powiadomienia. To niestety nie zastępuje. $var = isset($var) ? $var : 'default value'; Mówi, że w odpowiedzi ... po prostu wskazuję to ponownie każdemu, kto go przejrzy. :-D
Brad
6
Czy źle jest zrobić $ var = @ $ var?: 'Default value'; Jeśli tak, dlaczego? Biorąc pod uwagę, że jedynym „błędem” może być to, że zmienna $ nie jest ustawiona i że nie obchodzi nas, czy zmienna $ zmienna nie jest ustawiona ...
Codemonkey
8

Dzięki za wszystkie świetne odpowiedzi!

Dla każdego, kto przychodzi tutaj po ewentualną alternatywę, oto kilka funkcji, które pomagają usunąć nudę z tego rodzaju rzeczy.

function set_if_defined(&$var, $test){
    if (isset($test)){
        $var = $test;
        return true;
    } else {
        return false;
    }
}

function set_unless_defined(&$var, $default_var){
    if (! isset($var)){
        $var = $default_var;
        return true;
    } else {
        return false;
    }
}

function select_defined(){
    $l = func_num_args();
    $a = func_get_args();
    for ($i=0; $i<$l; $i++){
        if ($a[$i]) return $a[$i];
    }
}

Przykłady:

// $foo ||= $bar;
set_unless_defined($foo, $bar);

//$foo = $baz || $bletch
$foo = select_defined($baz, $bletch);

Jestem pewien, że można to poprawić.

Tom Auger
źródło
7

Popularnym idiomem zapewniającym zgodność ze starszymi wersjami PHP jest:

 $var = $bool   or   $var = "default";
 // If I use it, then only with excessive spaces for clarity.

Działa to dla wartości, które mogą być oceniane w kontekście logicznym. Zaletą jest to, że daje to również e_notice do debugowania, jeśli zmienna jest niezdefiniowana.

mario
źródło
Czy powiadomienie nie jest emitowane z $bool ? $bool : "default"if $boolnie jest zdefiniowane?
BoltClock
Jasne, to jest to samo. Założyłem, że OP odnosi się do isset($var) ? $var : DEFAULT. Ale wygląda na to, że i tak chce ich unikać.
mario
6

W PHP wcześniejszych niż 7. * można użyć?: Dla niezdefiniowanej zmiennej, której błędy są lokalnie pomijane przez @:

$foo = @$bar ?: $baz;
AndreyS Scherbakov
źródło
0

to kolejny dobry format issetsprawy

isset($foo) || $foo= $bar;

inny prosty sposób i da ci większą kontrolę, ponieważ możesz dodać więcej warunków i przypisać je do innej zmiennej w tym samym czasie

$foo = (isset($oData['foo']))?$bar['foo']:'default value';

Bassem Shahin
źródło
0

Możliwe rozwiązanie: defaultFor ()

Jeśli nie mamy rozwiązania fabrycznego (co jest rzeczywiście bardzo irytujące), poleciłbym poniższego małego pomocnika. W większości przypadków spełnia swoje zadanie:


    function defaultFor(&$x,$default=null) {
        if(!isset($x)) $x = $default;
    }

    //--------------------  Now you can do this: --------------

    defaultFor($a,"Jack");  // if $a is not set, it will be "Jack"
    defaultFor($x);         // no more notices for $x but keep it !isset

Mam nadzieję, że jest to blisko tego, co chciałeś osiągnąć. Nie da ci żadnych powiadomień, jeśli użyjesz go z nieistniejącą zmienną i jest to całkiem wygodne. Z pewnością ma wadę: wartość domyślna zawsze jest obliczana z góry, więc nie używaj jej z niczym ciężkim jako drugim parametrem, jak file_get_contents lub coś w tym rodzaju. W takich przypadkach lepiej jest setingować.

dkellner
źródło
0

Myślę, że ogólnie robię coś takiego:

$foo = $bar || $baz;

jest to zły pomysł, chyba że $bari $bazto zarówno wartości logiczne. Jeśli nie:

$bar = 10;
$baz = 11;

wtedy pojawia się pytanie: co decyduje o tym, czy coś jest prawdziwe, czy fałszywe? Większość ludzi prawdopodobnie spodziewałaby się, że zero będzie fałszywe, a wszystko inne będzie prawdziwe. Ale z niektórymi językami (na przykład Ruby), tylko falsei nilsą fałszywe, co oznacza oba te języki 0i 1byłoby prawdą. Z powodu tej dwuznaczności międzyjęzykowej myślę, że najlepiej będzie wyrazić się jasno w tych przypadkach:

if ($bar !== 0) {
   $foo = $bar;
} else {
   $foo = $baz;
}

lub:

$foo = $bar !== 0 ? $bar : $baz;
Steven Penny
źródło