Funzione di coalescenza per PHP?


131

Molti linguaggi di programmazione hanno una funzione di coalescenza (restituisce il primo valore non NULL, ad esempio ). PHP, purtroppo nel 2009, no.

Quale sarebbe un buon modo per implementarne uno in PHP fino a quando PHP stesso non avrà una funzione di coalescenza?


11
Correlati: il nuovo operatore a coalescenza nulla ?? per PHP 7.
Kojiro,

Ulteriori informazioni sull'operatore di coalescenza nulla sono disponibili qui - stackoverflow.com/questions/33666256/…
Peter

1
Giusto per notare, PHP7 ha implementato questa versione
Grzegorz il

@Grzegorz: un operatore non è una funzione, o dove l'hai trovata nuova in PHP 7;)
hakre

Per funzione non intendevo funzione;) Caratteristica. Non ero preciso. Grazie :)
Grzegorz,

Risposte:


194

C'è un nuovo operatore in php 5.3 che fa questo: ?:

// A
echo 'A' ?: 'B';

// B
echo '' ?: 'B';

// B
echo false ?: 'B';

// B
echo null ?: 'B';

Fonte: http://www.php.net/ChangeLog-5.php#5.3.0


25
Che dire delle scorciatoie ternarie multiple, sarebbe qualcosa come "echo $ a?: $ B?: $ C?: $ D;" lavoro?
ChrisR,

5
Non funziona come previsto per gli array. Ad esempio, quando si tenta di verificare se un elemento dell'array non definito è falso, si verificherà un errore. $input['properties']['range_low'] ?: '?'
Keyo,

5
Dovresti ricevere un avviso sull'Indice indefinito indipendentemente dall'utilizzo dell'operatore di coalescenza.
Kevin,

2
Più argomenti falsey restituiscono l'ultimo argomento, array() ?: null ?: falserestituisce false. L'operatore è davvero sano di mente.
Brad Koch,

6
Tieni presente che questo non accetta solo la non-null come la coalescenza in altre lingue, ma qualsiasi valore, che verrà convertito implicitamente in un valore booleano. Quindi assicurati di rispolverare le tue regole di cast di tipo
DanMan,

65

PHP 7 ha introdotto un vero operatore di coesione :

echo $_GET['doesNotExist'] ?? 'fallback'; // prints 'fallback'

Se il valore prima di ??non esiste o è nullil valore dopo che ??viene preso.

Il miglioramento rispetto ?:all'operatore menzionato è che ??gestisce anche variabili non definite senza lanciare un E_NOTICE.


Finalmente non più isset () e empty () dappertutto!
George Kagan,

7
@timeNomad avrai ancora bisogno è vuoto, controlla solo null
Nabeel Khan

L'unico modo per ottenere una "falsa fusione" sicura è usare un po 'di entrambi:($_GET['doesNotExist'] ?? null) ?: 'fallback'
Nathan Baulch,

Il vantaggio di ?:over ??, tuttavia, è che unisce anche valori vuoti, cosa ??che non funziona. Simile al comportamento dell'operatore logico OR in JavaScript (cioè $val || 'default'), troverei?: una forma più pratica di coalescenza se nella nostra pratica alla fine ci troviamo a gestire sia il vuoto che il nulla allo stesso modo (cioè $val ?: 'default'). E se vuoi forzare ulteriormente il problema e ingoiare E_NOTICE, potresti argomentare anche questo:echo @$val ?: 'default';
Matt Borja

29

Primo successo per "php coalesce" su google.

function coalesce() {
  $args = func_get_args();
  foreach ($args as $arg) {
    if (!empty($arg)) {
      return $arg;
    }
  }
  return NULL;
}

http://drupial.com/content/php-coalesce


9
Salva un po 'di ram e non duplicare gli arg in un array, fai solo foreach (func_get_args () come $ arg) {}
TravisO,

17
@ [Alfred, Ciaran] - non sei corretto. foreach () valuta il primo argomento una sola volta, per ottenere un array, e quindi scorre su di esso.
gahooa,

6
Mettere func_get_args () all'interno del foreach (qui come $ arg) non cambierà nulla dal punto di vista delle prestazioni.
Savageman,

7
@Savageman ... esattamente ... se stai pensando di spremere questo millisecondo di prestazioni o pochi byte di memoria dalla tua applicazione, probabilmente stai osservando il collo di bottiglia di prestazioni / memoria
errato

4
Ironia della sorte, questo è ora il primo successo di "php coalesce" su Google.
Will Shaver,

18

Mi piace molto l'operatore?:. Sfortunatamente, non è ancora implementato nel mio ambiente di produzione. Quindi uso l'equivalente di questo:

function coalesce() {
  return array_shift(array_filter(func_get_args()));
}

1
si tratta di una coalizione "veritiera", usando array_filter per sbarazzarsi di tutto ciò che viene valutato falso (incluso null) negli argomenti n passati. La mia ipotesi sta usando shift invece del primo elemento dell'array è in qualche modo più robusto, ma quello parte non lo so. vedi: php.net/manual/it/…
Adam Tolley,

3
Mi piace ma devo essere d'accordo con @hakre - coalescedovrebbe restituire il primo argomento non nullo che incontra, che includerebbe FALSE. Questa funzione FALSEperò scarterà , probabilmente non quello che op ha in mente (almeno non quello che vorrei da una coalescefunzione).
Madbreaks,

1
Solo le variabili devono essere passate per riferimento
Ben Sinclair,

9

Vale la pena notare che a causa del trattamento con PHP delle variabili non inizializzate e degli indici di array, qualsiasi tipo di funzione di coalescenza è di utilità limitata. Mi piacerebbe poter fare questo:

$id = coalesce($_GET['id'], $_SESSION['id'], null);

Ma questo, nella maggior parte dei casi, causerà l'errore PHP con un E_NOTICE. L'unico modo sicuro per testare l'esistenza di una variabile prima di usarla è usarla direttamente in empty () o isset (). L'operatore ternario suggerito da Kevin è l'opzione migliore se sai che tutte le opzioni della tua coalizione sono note per essere inizializzate.


In questo caso, i sindacati di array funzionano abbastanza bene ( $getstuff = $_GET+$_SESSION+array('id'=>null);$id=$getstuff['id'];).
Brilliand,

@ Quill cosa dovrebbe significare? Hai suggerito la soluzione con riferimento?
Ben Sinclair,

PHP 7 introduce l'adorabile nuovo operatore ternario isset?? per rendere più concisa questa operazione molto comune.
botimer,

6

Assicurati di identificare esattamente come vuoi che questa funzione funzioni con determinati tipi. PHP ha una vasta gamma di funzioni di controllo del tipo o simili, quindi assicurati di sapere come funzionano. Questo è un confronto di esempio di is_null () e empty ()

$testData = array(
  'FALSE'   => FALSE
  ,'0'      => 0
  ,'"0"'    => "0"  
  ,'NULL'   => NULL
  ,'array()'=> array()
  ,'new stdClass()' => new stdClass()
  ,'$undef' => $undef
);

foreach ( $testData as $key => $var )
{
  echo "$key " . (( empty( $var ) ) ? 'is' : 'is not') . " empty<br>";
  echo "$key " . (( is_null( $var ) ) ? 'is' : 'is not')  . " null<br>";
  echo '<hr>';
}

Come puoi vedere, empty () restituisce true per tutti questi, ma is_null () lo fa solo per 2 di essi.


2

Mi sto espandendo sulla risposta pubblicata da Ethan Kent . Quella risposta eliminerà gli argomenti non nulli che valutano come falsi a causa del funzionamento interno di array_filter , che non è ciò che una coalescefunzione in genere fa. Per esempio:

echo 42 === coalesce(null, 0, 42) ? 'Oops' : 'Hooray';

Spiacenti

Per ovviare a questo, sono necessari un secondo argomento e la definizione della funzione. La funzione richiamabile è responsabile del dire array_filterse aggiungere o meno il valore corrente dell'array all'array dei risultati:

// "callable"
function not_null($i){
    return !is_null($i);  // strictly non-null, 'isset' possibly not as much
}

function coalesce(){
    // pass callable to array_filter
    return array_shift(array_filter(func_get_args(), 'not_null'));
}

Sarebbe bello se potessi semplicemente passare isseto 'isset'come secondo argomento a array_filter, ma nessuna tale fortuna.


0

Attualmente sto usando questo, ma mi chiedo se non potrebbe essere migliorato con alcune delle nuove funzionalità di PHP 5.

function coalesce() {
  $args = func_get_args();
  foreach ($args as $arg) {
    if (!empty($arg)) {
    return $arg;
    }
  }
  return $args[0];
}

0

PHP 5.3+, con chiusure:

function coalesce()
{
    return array_shift(array_filter(func_get_args(), function ($value) {
        return !is_null($value);
    }));
}

Demo: https://eval.in/187365


Solo le variabili dovrebbero essere passate per riferimento
Ben Sinclair,

Sì, ho infranto le rigide regole della demo, solo per renderlo semplice. :)
Paulo Freitas,
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.