A melhor maneira de atribuir um valor padrão a uma variável (simule Perl ||, || =)

134

Adoro fazer esse tipo de coisa no Perl: $foo = $bar || $bazatribuir $baza $fooif $baré vazio ou indefinido. Você também tem $foo ||= $bletchque só irá atribuir $bletcha $foose $foonão estiver definido ou vazio.

O operador ternário nessa situação é tedioso e cansativo. Certamente, existe um método simples e elegante disponível em PHP?

Ou a única resposta é uma função personalizada que usa isset ()?

Tom Auger
fonte
1
Entre os operadores Perl com a funcionalidade desejada, existem //e //=existem a partir do Perl v5.10.0. O original ||e o ||=teste para o valor lógico, não para a definição.
Palec 8/08/15
@Palec, por que uma pergunta de 4 anos com 29 votos positivos seria identificada como uma duplicata de uma pergunta de 1 ano com 6 votos positivos (que em si foi marcada como duplicata de outra pergunta?) Acho que há um grande valor em manter isso pergunta, como o título é mais genérico (não faz referência à resposta, ou seja: isset ()).
Tom Auger
São duplicados claros e exatos. Ele admite que não pensei muito sobre qual deveria ser o original, estava no meio de outra coisa, fazer um elo entre os dois era o objetivo. Recolhendo meu VTC.
Palec
Uma duplicata exata, marcada (IMO erroneamente) como duplicada de outra pergunta: abreviação de PHP para isset ()?
Palec

Respostas:

130

No PHP 7, finalmente temos uma maneira de fazer isso com elegância. É chamado de operador coalescente nulo . Você pode usá-lo assim:

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

Isso é equivalente a

$name = isset($_GET['name']) ? $_GET['name']:'john doe';
jpschroeder
fonte
14
Eu diria que o operador da nave espacial também tem mérito.
Mariano
3
Eu pensei que Mariano estava puxando nossas pernas, mas não, é uma coisa <=>e bastante precisa para inicializar!
HPWD 14/06
1
Observe que o operador coalescente nulo se comporta de maneira diferente do operador condicional, pois é específico para um nullvalor. Por exemplo, se $_GET['name']estiver definido como uma string vazia, a primeira linha retornará uma string vazia, mas poderíamos retornar "john doe" usando $_GET['name'] ? $_GET['name'] : 'john doe'.
VPhantom
211

O PHP 5.3 possui um ?:operador abreviado :

$foo = $bar ?: $baz;

Que atribui $barse não for um valor vazio (não sei como isso seria diferente no PHP do Perl), caso contrário $baz, e é o mesmo que esse no Perl e nas versões anteriores do PHP:

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

Mas o PHP não possui um operador de atribuição composto para isso (ou seja, não é equivalente ao Perl ||=).

Além disso, o PHP fará barulho se $barnão estiver definido, a menos que você desative os avisos. Há também uma diferença semântica entre isset()e empty(). O primeiro retorna false se a variável não existir ou estiver definida como NULL. Este último retorna true se ela não existe, ou é definida como 0, '', falseou NULL.

BoltClock
fonte
2
+1 Por me apresentar mais um ótimo recurso do 5.3, estou perdendo meus servidores RHEL5 / PHP5.1.2.
Michael Berkowski
Eu acho que você quer dizer em The first returnsvez de The secondem sua penúltima sentença.
Toto
21
Note que se sua variável é indefinida, o PHP lançará avisos sobre ela. Infelizmente, isso não é um substituto para $var = isset($var) ? $var : 'default value'; Ele diz que na resposta ... apenas apontá-lo novamente para qualquer pessoa que o deslize. :-D
Brad
6
É ruim fazer $ var = @ $ var?: 'Valor padrão'; Se sim, por quê? Dado que o único "erro" pode ser que $ var não está definido, e que nós não nos importamos se $ var não está definido ...
Codemonkey
8

Obrigado por todas as ótimas respostas!

Para qualquer pessoa que venha aqui para uma possível alternativa, aqui estão algumas funções que ajudam a eliminar o tédio desse tipo de coisa.

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

Exemplos:

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

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

Tenho certeza que isso pode ser melhorado.

Tom Auger
fonte
7

Um idioma comum para se manter compatível com versões mais antigas do PHP é:

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

Isso funciona para valores que podem ser avaliados no contexto booleano. A vantagem aqui é que ele também fornece o debug e_notice, caso a variável seja indefinida.

mario
fonte
Um aviso não é emitido $bool ? $bool : "default"se $boolnão estiver definido?
BoltClock
Claro, é a mesma coisa. Eu assumi OP está se referindo isset($var) ? $var : DEFAULT. Mas parece que ele quer evitá-los de qualquer maneira.
Mario
6

No PHP anterior a 7. *, pode-se usar?: Para uma variável indefinida com erros suprimidos localmente com um @:

$foo = @$bar ?: $baz;
AndreyS Scherbakov
fonte
0

esse é outro bom formato para o issetcaso

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

outra maneira simples e lhe dará mais controle, pois você pode adicionar mais condições e atribuir a outra variável ao mesmo tempo

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

Bassem Shahin
fonte
0

Uma solução possível: defaultFor ()

A menos que tenhamos uma solução de fábrica (que é realmente muito irritante), eu recomendaria o seguinte ajudante. Ele faz o trabalho na maioria dos casos:


    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

Espero que isso seja próximo do que você queria alcançar. Não será emitido nenhum aviso se você o usar com uma variável inexistente, e é bastante conveniente. Certamente, ele tem uma desvantagem: o valor padrão sempre é calculado de antemão, portanto, não o use com nada pesado como segundo parâmetro, como um file_get_contents ou algo assim. Nesses casos, você está melhor com a emissão.

dkellner
fonte