La mejor manera de dar a una variable un valor predeterminado (simular Perl ||, || =)

134

Me encanta hacer este tipo de cosas en Perl: $foo = $bar || $bazasignar $baza $foosi $barestá vacío o indefinido. También tiene $foo ||= $bletchque sólo se asigne $bletcha $foosi $foono está definido o vaciar.

El operador ternario en esta situación es tedioso y cansado. ¿Seguramente hay un método simple y elegante disponible en PHP?

¿O es la única respuesta una función personalizada que usa isset ()?

Tom Auger
fuente
1
Por cierto, los operadores de Perl con la funcionalidad deseada son //y //=existen a partir de Perl v5.10.0. El original ||y ||=prueba de valor lógico, no de definición.
Palec
@Palec, ¿por qué una pregunta de 4 años con 29 votos a favor se identifica como un duplicado de una pregunta de 1 año con 6 votos a favor (que en sí se marcó como un duplicado de otra pregunta)? Creo que hay un gran valor en mantener esto pregunta, ya que el título es más genérico (no hace referencia a la respuesta, es decir: isset ()).
Tom Auger
Son duplicados claros y exactos. Admite que no pensé mucho en cuál debería ser el original, estaba en el medio de otra cosa, hacer un enlace entre los dos era el objetivo. Retractando mi VTC.
Palec
Un duplicado exacto, marcado (IMO erróneamente) como un duplicado de otra pregunta: ¿ Taquigrafía PHP para isset ()?
Palec

Respuestas:

130

En PHP 7 finalmente tenemos una manera de hacerlo con elegancia. Se llama el operador de fusión nula . Puedes usarlo así:

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

Esto es equivalente a

$name = isset($_GET['name']) ? $_GET['name']:'john doe';
jpschroeder
fuente
14
Yo diría que el operador de la nave espacial también tiene mérito.
Mariano
3
Pensé que Mariano tiraba de nuestras piernas, pero no, ¡es una cosa <=>y bastante precisa para arrancar!
HPWD
1
Tenga en cuenta que el operador de fusión nula se comporta de manera diferente al operador condicional, ya que es específico de un nullvalor. Por ejemplo, si $_GET['name']se establece en una cadena vacía, la primera línea devolvería una cadena vacía, pero podríamos devolver "john doe" usando $_GET['name'] ? $_GET['name'] : 'john doe'.
VPhantom
211

PHP 5.3 tiene un ?:operador abreviado :

$foo = $bar ?: $baz;

Que asigna $barsi no es un valor vacío (no sé cómo sería diferente en PHP de Perl), de lo contrario $baz, y es el mismo que esto en Perl y versiones anteriores de PHP:

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

Pero PHP no tiene un operador de asignación compuesto para esto (es decir, no es equivalente a Perl ||=).

Además, PHP hará ruido si $barno está configurado a menos que desactive los avisos. También hay una diferencia semántica entre isset()y empty(). El primero devuelve falso si la variable no existe o se establece en NULL. Este último responde cierto si éste no existe, o se establece en 0, '', falseo NULL.

BoltClock
fuente
2
+1 Por presentarme otra gran característica de 5.3 que me estoy perdiendo en mis servidores RHEL5 / PHP5.1.2.
Michael Berkowski
Supongo que quieres decir en The first returnslugar de The seconden tu penúltima oración.
Toto
21
Tenga en cuenta que si su variable no está definida, PHP lanzará avisos al respecto. Esto, desafortunadamente, no es un reemplazo para $var = isset($var) ? $var : 'default value'; Dice que en la respuesta ... solo lo señala de nuevo para cualquiera que lo lea. :-D
Brad
66
¿Es malo hacer $ var = @ $ var?: 'Valor predeterminado'; Si es así, ¿por qué? Teniendo en cuenta que el único "error" podría ser que $ var no está definida, y que no les importa si $ var no se establece ...
codemonkey
8

¡Gracias por todas las excelentes respuestas!

Para cualquiera que venga aquí por una posible alternativa, aquí hay algunas funciones que ayudan a eliminar el tedio de este tipo de cosas.

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

Ejemplos:

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

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

Estoy seguro de que se pueden mejorar.

Tom Auger
fuente
7

Un modismo común para seguir siendo compatible con versiones anteriores de PHP es:

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

Esto funciona para valores que pueden evaluarse en contexto booleano. La ventaja aquí es que también le da dicho debug e_notice si la variable no está definida.

mario
fuente
¿No se emite un aviso $bool ? $bool : "default"si $boolno está definido?
BoltClock
Claro, eso es lo mismo. Asumí que OP se está refiriendo isset($var) ? $var : DEFAULT. Pero parece que quiere evitarlos de todos modos.
Mario
6

En PHP anterior a 7. *, uno puede usar?: Para una variable indefinida que tiene errores localmente suprimidos con un @:

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

este es otro buen formato para el issetcaso

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

Otra forma simple y le dará más control, ya que puede agregar más condiciones y asignar a otra variable al mismo tiempo

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

Bassem Shahin
fuente
0

Una posible solución: defaultFor ()

A menos que tengamos una solución de fábrica (que de hecho es muy molesta), recomendaría el siguiente pequeño ayudante. Hace el trabajo en la mayoría de los 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 esto esté cerca de lo que querías lograr. No le dará ningún aviso si lo usa con una variable inexistente, y es bastante conveniente. Seguramente tiene un inconveniente: el valor predeterminado siempre se calcula de antemano, así que no lo use con nada pesado como segundo parámetro, como file_get_contents o algo así. En esos casos, es mejor con isseting.

dkellner
fuente