Função de coalescência para PHP?

131

Muitas linguagens de programação possuem uma função de coalescência (retorna o primeiro valor não NULL, por exemplo ). PHP, infelizmente em 2009, não.

Qual seria uma boa maneira de implementar um no PHP até que o próprio PHP obtenha uma função de coalescência?

mikl
fonte
11
Relacionado: o novo operador nulo coalescentes ?? para PHP 7.
kojiro
Mais informações sobre o operador nulo coalesce pode ser encontrado aqui - stackoverflow.com/questions/33666256/...
Peter
1
Apenas a nota, PHP7 implementado este fucntion
Grzegorz
@Grzegorz: Um operador não é uma função, ou onde você achou que a função nova no PHP 7;)
hakre
Por função, eu não quis dizer função;) Característica. Eu não era preciso. Obrigado :)
Grzegorz

Respostas:

194

Existe um novo operador no php 5.3 que faz isso: ?:

// 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

Kevin
fonte
25
Que tal vários atalhos ternários, algo como "echo $ a?: $ B?: $ C?: $ D;" trabalhos?
ChrisR
5
Não funciona como esperado para matrizes. Por exemplo, ao tentar verificar se um elemento de matriz indefinido é falsey, resultará em um erro. $input['properties']['range_low'] ?: '?'
Keyo 12/07/11
5
Você deve receber um aviso de Índice indefinido, independentemente do uso do operador de coalescência.
Kevin
2
Vários argumentos falsey retornam o último argumento, array() ?: null ?: falseretornam false. O operador é realmente são.
Brad Koch
6
Lembre-se de que isso não aceita apenas valores não nulos como coalescência em outros idiomas, mas qualquer valor que será implicitamente convertido em um booleano. Portanto, certifique-se de escovar acima em suas regras de fundição do tipo
DanMan
65

O PHP 7 introduziu um operador de coalescência real :

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

Se o valor anterior ao ??não existir ou for nullo valor posterior ao ??obtido.

A melhoria em relação ao ?:operador mencionado é que ele ??também lida com variáveis ​​indefinidas sem gerar um E_NOTICE.

flori
fonte
Finalmente, não há mais isset () e vazio () em todo o lugar!
9788 George Kagan #
7
@timeNomad você ainda necessidade é vazio, ele verifica única nula
Nabeel Khan
A única maneira de obter segurança "falsy-coalalesce" é usar um pouco dos dois:($_GET['doesNotExist'] ?? null) ?: 'fallback'
Nathan Baulch
A vantagem do ?:excesso ??, no entanto, é que ele une valores vazios, o que ??não funciona. Semelhante ao comportamento do operador OR lógico em JavaScript (ie $val || 'default'), eu consideraria ?:uma forma mais prática de coalescer se, em nossa prática, finalmente nos encontrarmos lidando com vazio e nulo da mesma maneira (ie $val ?: 'default'). E se você quiser forçar a questão ainda mais e engolir E_NOTICE, você pode argumentar isso até:echo @$val ?: 'default';
Matt Borja
29

Primeiro hit para "php coalesce" no 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
fonte
9
Guardar um pouco de memória RAM e não duplicar os argumentos em um array, basta fazer foreach (func_get_args () como $ arg) {}
TravisO
17
@ [Alfred, Ciaran] - você está incorreto. O foreach () avalia o primeiro argumento apenas uma vez, para obter uma matriz e, em seguida, itera sobre ele.
gahooa
6
Colocar func_get_args () dentro do foreach (aqui como $ arg) não mudará nada do ponto de vista do desempenho.
Savageman
7
@Savageman ... exatamente ... se você está pensando em apertar esse milésimo de segundo de desempenho ou alguns bytes de memória para fora do seu aplicativo que você está olhando provavelmente o gargalo performance / memória errado
ChrisR
4
Ironicamente, este é agora o primeiro hit de "php coalesce" no Google.
Will Shaver
18

Eu realmente gosto do operador?:. Infelizmente, ainda não foi implementado no meu ambiente de produção. Então, eu uso o equivalente a isso:

function coalesce() {
  return array_shift(array_filter(func_get_args()));
}
Ethan Kent
fonte
1
esta é uma coalizão 'truthy', usar array_filter para se livrar de qualquer coisa avaliada como falsa (incluindo nula) nos n argumentos passados. Meu palpite é que usar shift em vez do primeiro elemento da matriz é de alguma forma mais robusto, mas isso parte que eu não sei. Veja: php.net/manual/en/…
Adam Tolley
3
Eu gosto, mas tenho que concordar com @hakre - coalescedeve retornar o primeiro argumento não nulo que encontrar, o que incluiria FALSE. Essa função descartará FALSE, provavelmente, não o que o op tem em mente (pelo menos não o que eu gostaria que fosse de uma coalescefunção).
Madbreaks
1
Apenas variáveis devem ser passados por referência
Ben Sinclair
9

Vale a pena notar que, devido ao tratamento do PHP de variáveis ​​não inicializadas e índices de matriz, qualquer tipo de função de coalescência é de uso limitado. Eu adoraria poder fazer isso:

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

Mas isso, na maioria dos casos, causa erro no PHP com um E_NOTICE. A única maneira segura de testar a existência de uma variável antes de usá-la é usá-la diretamente em empty () ou isset (). O operador ternário sugerido por Kevin é a melhor opção se você souber que todas as opções em sua coalescência são conhecidas por serem inicializadas.

Andrew
fonte
Nesse caso, as uniões de matriz funcionam muito bem ( $getstuff = $_GET+$_SESSION+array('id'=>null);$id=$getstuff['id'];).
Brilliand
@ Quill, o que isso significa? Você sugeriu a solução com referência?
Ben Sinclair
O PHP 7 apresenta o adorável novo operador ternário isset?? para tornar essa operação muito comum mais concisa.
botimer 11/09/15
6

Certifique-se de identificar exatamente como deseja que essa função funcione com certos tipos. O PHP possui uma grande variedade de verificação de tipo ou funções similares, portanto, saiba como elas funcionam. Esta é uma comparação de exemplo de 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>';
}

Como você pode ver, empty () retorna true para todos esses itens, mas is_null () somente o faz para dois deles.

Peter Bailey
fonte
2

Estou expandindo a resposta postada por Ethan Kent . Essa resposta descartará argumentos não nulos que são avaliados como falsos devido ao funcionamento interno do array_filter , que não é o que uma coalescefunção normalmente faz. Por exemplo:

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

Opa

Para superar isso, é necessário um segundo argumento e definição de função. A função solicitável é responsável por informar array_filterse deve ou não adicionar o valor atual da matriz à matriz de resultados:

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

Seria bom se você pudesse simplesmente passar issetou 'isset'como o segundo argumento para array_filter, mas não teve essa sorte.

Madbreaks
fonte
0

Atualmente, estou usando isso, mas gostaria de saber se não poderia ser melhorado com alguns dos novos recursos do PHP 5.

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

PHP 5.3+, com encerramentos:

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

Demo: https://eval.in/187365

Paulo Freitas
fonte
Apenas variáveis devem ser passados por referência
Ben Sinclair
Sim, eu quebrei as regras estritas da demonstração, apenas para simplificar. :)
Paulo Freitas