Il modo migliore per assegnare a una variabile un valore predefinito (simulare Perl ||, || =)


134

Adoro fare questo genere di cose in Perl: $foo = $bar || $bazassegnare $baza $foose $barè vuoto o indefinito. Hai anche $foo ||= $bletchche solo assegnare $bletcha $foose $foonon è definito o svuotare.

L'operatore ternario in questa situazione è noioso e noioso. Sicuramente esiste un metodo semplice ed elegante disponibile in PHP?

Oppure l'unica risposta è una funzione personalizzata che utilizza isset ()?



1
A proposito, gli operatori Perl con le funzionalità desiderate sono //ed //=esistono a partire da Perl v5.10.0. L'originale ||e ||=verifica il valore logico, non la definizione.
Palec

@Palec, perché una domanda di 4 anni con 29 voti positivi dovrebbe essere identificata come un duplicato di una domanda di 1 anno con 6 voti positivi (che a sua volta è stata contrassegnata come duplicata di un'altra domanda?) Penso che ci sia un grande valore nel mantenere questo domanda, poiché il titolo è più generico (non fa riferimento alla risposta, ad esempio: isset ()).
Tom Auger

Sono duplicati chiari ed esatti. Ammetto che non pensavo molto a quale dovrebbe essere l'originale, ero nel mezzo di qualcos'altro, fare un collegamento tra i due era l'obiettivo. Ritirare il mio VTC.
Palec,

Un duplicato esatto, contrassegnato (erroneamente IMO) come duplicato di un'altra domanda: abbreviazione di PHP per isset ()?
Palec,

Risposte:


131

In PHP 7 abbiamo finalmente un modo per farlo elegantemente. Si chiama operatore a coalescenza Null . Puoi usarlo in questo modo:

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

Questo equivale a

$name = isset($_GET['name']) ? $_GET['name']:'john doe';

14
Direi che anche l' operatore dell'astronave ha dei meriti.
Mariano,

3
Pensavo che Mariano ci stesse tirando le gambe, ma no, è una cosa <=>abbastanza accurata da avviare!
HPWD,

1
Si noti che l'operatore di coalescenza null si comporta in modo diverso dall'operatore condizionale, in quanto è specifico di un nullvalore. Ad esempio, se $_GET['name']è impostato su una stringa vuota, la prima riga restituirà una stringa vuota, ma potremmo restituire "john doe" utilizzando $_GET['name'] ? $_GET['name'] : 'john doe'.
VPhantom

211

PHP 5.3 ha un ?:operatore abbreviato :

$foo = $bar ?: $baz;

Che assegna $barse non è un valore vuoto (non so come sarebbe diverso in PHP da Perl), altrimenti $baz, ed è lo stesso di questo in Perl e versioni precedenti di PHP:

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

Ma PHP non ha un operatore di assegnazione composto per questo (cioè, nessun equivalente di Perl ||=).

Inoltre, PHP farà rumore se $barnon è impostato a meno che non disattivi gli avvisi. C'è anche una differenza semantica tra isset()e empty(). Il primo restituisce false se la variabile non esiste o è impostata su NULL. Quest'ultimo ritorna vero se non esiste, o è impostato su 0, '', falseo NULL.


2
+1 Per avermi fatto conoscere un'altra fantastica funzionalità di 5.3, mi sto perdendo nei miei server RHEL5 / PHP5.1.2.
Michael Berkowski,

Immagino che intendi The first returnsinvece che The secondnella tua penultima frase.
Tot

21
Nota che se la tua variabile non è definita, PHP noterà qualcosa al riguardo. Questo, sfortunatamente, non è un sostituto di $var = isset($var) ? $var : 'default value'; Si dice che nella risposta ... sottolineandolo di nuovo per chiunque lo sfoglia. MrGreen
Brad

6
È male fare $ var = @ $ var?: 'Valore predefinito'; Se è così, perché? Dato che l'unico "errore" potrebbe essere che $ var non è impostato e che non ci importa se $ var non è impostato ...
Codemonkey

8

Grazie per tutte le ottime risposte!

Per chiunque venga qui per una possibile alternativa, ecco alcune funzioni che aiutano a togliere il tedio da questo genere di cose.

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];
    }
}

Esempi:

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

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

Sono sicuro che questi possono essere migliorati.


7

Un linguaggio comune per rimanere compatibile con le versioni precedenti di PHP è:

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

Funziona con valori che possono essere valutati in un contesto booleano. Il vantaggio qui è che ti dà anche detto e_notice di debug se la variabile non fosse definita.


Non viene emesso un avviso $bool ? $bool : "default"se $boolnon è definito?
BoltClock

Certo, è lo stesso. Supponevo che OP si riferisse a isset($var) ? $var : DEFAULT. Ma sembra che voglia evitarli comunque.
mario,

6

In PHP precedente a 7. *, si può usare?: Per una variabile non definita con errori localmente eliminati con un @:

$foo = @$bar ?: $baz;

0

questo è un altro buon formato per il issetcaso

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

un altro modo semplice e ti darà un maggiore controllo in quanto puoi aggiungere più condizioni e assegnare a un'altra variabile contemporaneamente

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


0

Una possibile soluzione: defaultFor ()

A meno che non abbiamo una soluzione di fabbrica (che è davvero molto fastidiosa), consiglierei il seguente piccolo aiutante. Fa il lavoro nella maggior parte dei casi:


    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

Spero che questo sia vicino a ciò che volevi ottenere. Non ti darà alcun avviso se lo usi con una variabile inesistente, ed è abbastanza conveniente. Sicuramente ha uno svantaggio: il valore predefinito viene sempre calcolato in anticipo, quindi non usarlo con qualcosa di pesante come secondo parametro, come un file_get_contents o qualcosa del genere. In questi casi, stai meglio con l'emissione.


0

Penso che in generale faccia qualcosa del genere:

$foo = $bar || $baz;

è una cattiva idea, a meno $barche non $bazsiano entrambi booleani. Se non sono:

$bar = 10;
$baz = 11;

allora la domanda diventa: cosa determina se qualcosa è vero o falso? La maggior parte delle persone si aspetterebbe probabilmente che lo zero sia falso e tutto il resto sia vero. Ma con alcune lingue (ad esempio Ruby), solo falsee nilsono false, il che significa entrambe 0e 1sarebbe vero. A causa di questa ambiguità linguistica, penso che sia meglio essere espliciti in questi casi:

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

o:

$foo = $bar !== 0 ? $bar : $baz;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.