Fonction de coalescence pour PHP?

131

De nombreux langages de programmation ont une fonction de fusion (renvoie la première valeur non NULL, par exemple ). PHP, malheureusement en 2009, ne le fait pas.

Quel serait un bon moyen d'en implémenter un en PHP jusqu'à ce que PHP lui-même obtienne une fonction de fusion?

Mikl
la source
11
En relation: le nouvel opérateur ?? de
fusion
Plus d'informations sur l'opérateur de fusion nul peuvent être trouvées ici - stackoverflow.com/questions/33666256/...
Peter
1
Juste pour noter, PHP7 a implémenté cette fonction
Grzegorz
@Grzegorz: Un opérateur n'est pas une fonction, ou où avez-vous trouvé cette fonction nouvelle dans PHP 7;)
hakre
Par fonction, je ne voulais pas dire fonction;) Caractéristique. Je n'ai pas été précis. Merci :)
Grzegorz

Réponses:

194

Il y a un nouvel opérateur dans php 5.3 qui fait ceci: ?:

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

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

// B
echo false ?: 'B';

// B
echo null ?: 'B';

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

Kevin
la source
25
Qu'en est-il des multiples raccourcis ternaires, est-ce que quelque chose comme "echo $ a?: $ B?: $ C?: $ D;" travail?
ChrisR
5
Ne fonctionne pas comme prévu pour les tableaux. Par exemple, lorsque vous essayez de vérifier si un élément de tableau non défini est faux, cela entraînera une erreur. $input['properties']['range_low'] ?: '?'
Keyo
5
Vous devriez recevoir un avis d'index indéfini indépendamment de l'utilisation de l'opérateur de fusion.
Kevin le
2
Plusieurs arguments faux retournent le dernier argument, array() ?: null ?: falseretourne false. L'opérateur est en effet sain d'esprit.
Brad Koch
6
Gardez à l'esprit que cela n'accepte pas seulement non-null comme coalesce dans d'autres langues, mais toute valeur, qui sera implicitement convertie en booléen. Alors assurez-vous de
revoir
65

PHP 7 a introduit un véritable opérateur de fusion :

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

Si la valeur avant le ??n'existe pas ou est nullla valeur après la ??prise.

L'amélioration par rapport à l' ?:opérateur mentionné est que le ??gère également les variables non définies sans lancer de fichier E_NOTICE.

flori
la source
Enfin plus de isset () et de vide () partout!
George Kagan
7
@timeNomad dont vous aurez toujours besoin est vide, il vérifie uniquement la valeur null
Nabeel Khan
La seule façon d'obtenir un "faux coalesce" sûr est d'utiliser un peu des deux:($_GET['doesNotExist'] ?? null) ?: 'fallback'
Nathan Baulch
L'avantage de ?:over ??, cependant, est qu'il fusionne également des valeurs vides, ce qui ??n'est pas le cas. Semblable au comportement de l'opérateur logique OR en JavaScript (c'est-à-dire $val || 'default'), je trouverais ?:une forme plus pratique de fusion si dans notre pratique nous nous retrouvons finalement à gérer à la fois vide et nul de la même manière (c'est-à-dire $val ?: 'default'). Et si vous voulez forcer le problème plus loin et avaler E_NOTICE, vous pouvez même argumenter ceci:echo @$val ?: 'default';
Matt Borja
29

Premier hit pour "php coalesce" sur google.

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

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

Will Shaver
la source
9
Économisez un tout petit peu de RAM et ne dupliquez pas les arguments dans un tableau, faites simplement foreach (func_get_args () as $ arg) {}
TravisO
17
@ [Alfred, Ciaran] - vous avez tort. foreach () évalue le premier argument une seule fois, pour obtenir un tableau, puis l'itère.
gahooa
6
Mettre func_get_args () dans le foreach (ici comme $ arg) ne changera rien du point de vue des performances.
Savageman
7
@Savageman ... exactement ... si vous songez à extraire cette milliseconde de performances ou quelques octets de mémoire de votre application, vous recherchez probablement le mauvais goulot d'étranglement en
termes de
4
Ironiquement, c'est maintenant le premier hit pour "php coalesce" sur Google.
Will Shaver
18

J'aime vraiment l'opérateur?:. Malheureusement, il n'est pas encore implémenté dans mon environnement de production. J'utilise donc l'équivalent de ceci:

function coalesce() {
  return array_shift(array_filter(func_get_args()));
}
Ethan Kent
la source
1
il s'agit d'une fusion «véridique», en utilisant array_filter pour se débarrasser de tout ce qui est évalué à faux (y compris nul) dans les n arguments passés. Je suppose que l'utilisation de shift au lieu du premier élément du tableau est en quelque sorte plus robuste, mais que partie je ne sais pas. voir: php.net/manual/en
Adam Tolley
3
Je l'aime mais je dois être d'accord avec @hakre - coalesceest censé renvoyer le premier argument non nul qu'il rencontre, qui inclurait FALSE. Cette fonction supprimera FALSEcependant, probablement pas ce que op a à l'esprit (du moins pas ce que je voudrais d'une coalescefonction).
Madbreaks
1
Seules les variables doivent être passées par référence
Ben Sinclair
9

Il est intéressant de noter qu'en raison du traitement par PHP des variables non activées et des indices de tableau, tout type de fonction de fusion est d'une utilisation limitée. J'adorerais pouvoir faire ceci:

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

Mais cela provoquera, dans la plupart des cas, une erreur PHP avec un E_NOTICE. Le seul moyen sûr de tester l'existence d'une variable avant de l'utiliser est de l'utiliser directement dans empty () ou isset (). L'opérateur ternaire suggéré par Kevin est la meilleure option si vous savez que toutes les options de votre fusion sont connues pour être initialisées.

Andrew
la source
Dans ce cas, les unions de tableaux fonctionnent assez bien ( $getstuff = $_GET+$_SESSION+array('id'=>null);$id=$getstuff['id'];).
Brilliand
@Quill qu'est-ce que ça veut dire? Avez-vous la solution suggérée avec référence?
Ben Sinclair
PHP 7 introduit le nouvel opérateur ternaire isset?? pour rendre cette opération très courante plus concise.
botimer le
6

Assurez-vous d'identifier exactement comment vous souhaitez que cette fonction fonctionne avec certains types. PHP a une grande variété de fonctions de vérification de type ou similaires, alors assurez-vous de savoir comment elles fonctionnent. Ceci est un exemple de comparaison de is_null () et 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>';
}

Comme vous pouvez le voir, empty () renvoie true pour tous ceux-ci, mais is_null () ne le fait que pour 2 d'entre eux.

Peter Bailey
la source
2

Je développe la réponse publiée par Ethan Kent . Cette réponse supprimera les arguments non nuls évalués à faux en raison du fonctionnement interne de array_filter , ce qui n'est pas ce qu'une coalescefonction fait généralement. Par exemple:

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

Oups

Pour surmonter cela, un deuxième argument et une définition de fonction sont nécessaires. La fonction appelable est chargée de dire array_filters'il faut ou non ajouter la valeur actuelle du tableau au tableau de résultats:

// "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'));
}

Ce serait bien si vous pouviez simplement passer issetou 'isset'comme deuxième argument array_filter, mais pas de chance.

Madbreaks
la source
0

J'utilise actuellement ceci, mais je me demande s'il ne pourrait pas être amélioré avec certaines des nouvelles fonctionnalités de PHP 5.

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

PHP 5.3+, avec fermetures:

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

Démo: https://eval.in/187365

Paulo Freitas
la source
Seules les variables doivent être passées par référence
Ben Sinclair
Ouais, j'ai enfreint les règles strictes de la démo, juste pour faire simple. :)
Paulo Freitas