tags:

views:

341

answers:

6

I'm wanting to assign a variable only it hasn't already been assigned. What's the PHP way of doing the following?

$result = null;
$result ||= check1();
$result ||= check2();
$result ||= "default";

I checked the standard operators and the is_null function, but there doesn't seem to be an easy way of doing the above operation.

+17  A: 

isset() is the usual way of doing this:

if (!isset($blah)) {
  $blah = 'foo';
}

Note: you can assign null to a variable and it will be assigned. This will yield different results with isset() and is_null() so you need to be clear on what you mean by "not assigned". See Null vs. isset(). This is also one case where you need to be careful about doing automatic type conversion, meaning using the !=/== or ===/!== depending on the desired result.

You can use boolean shorthand for this too (which is what the Perl ||= operator is). As of PHP 5.2.x there is no operator like you speak of. In Perl:

$a ||= $b;

is equivalent to:

$a = $a || $b;

You can do the second form in PHP but PHP has some funky rules about type juggling. See Converting to boolean:

When converting to boolean, the following values are considered FALSE:

  • the boolean FALSE itself
  • the integer 0 (zero)
  • the float 0.0 (zero)
  • the empty string, and the string "0"
  • an array with zero elements
  • an object with zero member variables (PHP 4 only)
  • the special type NULL (including unset variables)
  • SimpleXML objects created from empty tags

Every other value is considered TRUE (including any resource).

So after:

$a = 0;
$a = $a || 5;

$a would equal 5. Likewise:

$a = 0;
$b = '';
$c = $a == $b; // true
$d = $a === $b; // false

You have to watch out for these things.

cletus
$a = isset($a) ? $a : $b; is a shorthand for 1st code sample
niteria
$a = 0;$a = $a || 5;echo $a; // boolean TRUE
eyelidlessness
Oddly...echo $a == 5 ? 'true' : 'false'; // true- but -echo $a - 1; // 0
eyelidlessness
Sorry for comment-flooding... echo $a == 6 ? 'true' : 'false'; // true, so it seems the compared integer is being converted to boolean, rather than the boolean being converted to numeric. I know the automatic type conversion is a little wonky, but that's definitely not the behavior I expected. At any rate, I think it's clear that $a = $a || 5 doesn't work as advertised. It does, however, work that way in Javascript.
eyelidlessness
+2  A: 

How about using a couple of nested ternary operators?

For me it's the easiest way to deal with your problem. And since you can use nested ternary operators you should be able to add more checks if needed.

$var = isset($var) ? $var : ($i=check1()) ? $i : ($i=check2()) ? $i : "default" ;

It's almost the same amount of code and it should work.. unless I've misunderstood you. If that's the case I'm sorry.

In comparison with the original code you posted as example, the length is almost the same:

$result = null; $result ||= check1(); $result ||= check2(); $result ||= "default";
 - vs -
$var = isset($var) ? $var : ($i=check1()) ? $i : ($i=check2()) ? $i : "default" ;

Nested ternary operators can be a little bit confusing, so here you have it with comments:

    // Is $var set?
 $var = isset($var) ?
  // TRUE: It is, use $var
  $var :
  // FALSE: $var is not set, run check1
  ( $i=check1() ) ?
  // TRUE: the function check1 returned valid data
  $i :
  // FALSE: the function check1 returned null or false, run check2
  ($i=check2()) ?
  // TRUE:  the function check2 returned valid data
  $i :
  // FALSE: the function check1 returned null or false, set default value
  "default" ;
kuroir
+7  A: 
isset($foo) || $foo = 'bar';
erenon
That's cool. It seems obvious but I never would have thought to try it.
eyelidlessness
A: 

I haven't tried it yet, but have wanted to play with PECL Operator for ages.

Question Mark
+1  A: 

From php 5.3 you can use:

$result = $result ?: check1();
troelskn
+1  A: 

I came up with this function which has a side benefit of shutting up useless undefined variable notices. It's close enough to Javascript's behaviour for me:

function default_value(&$var, $default) {
    return isset($var) ? $var : $default;
}

$want_something = default_value($_POST['mightbeunset'], false);
Ant P.