481

I was diving into Symfony framework (version 4) code and found this piece of code:

$env = $_SERVER['APP_ENV'] ?? 'dev';

I'm not sure what this actually does but I imagine that it expands to something like:

$env = $_SERVER['APP_ENV'] != null ? $_SERVER['APP_ENV'] : 'dev';

Or maybe:

$env = isset($_SERVER['APP_ENV']) ? $_SERVER['APP_ENV'] : 'dev';

Does someone have any precision about the subject?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
elkolotfi
  • 5,645
  • 2
  • 15
  • 19
  • 1
    https://stackoverflow.com/a/3737177/5897602 – Jaquarh Dec 04 '18 at 10:21
  • 3
    I've just discovered this question and reading your edit I felt to point out why you are wrong. You don't need to know the operator's name to find it, simply because I think it is pretty obvious that the double "??" could only be an "operator" in PHP (_specially looking at the syntax in example_), so this simple assumption was enough to try to search "php operators" or "php 7 operators" on google (_paying attention to the PHP version required by symfony 4_) to find the answer much faster than writing the question here (_on where, using the same assumption, you would found the duplicate_). – gp_sflover Dec 04 '18 at 14:01
  • 11
    @gp_sflover for "php 7 operators" ok, you have chances to find it. With "php operator"...good luck :) And that's what anyone who never saw it before would do In my opinion it's not completely intuitive to think that this is a new feature that was only included in the latest version of php. Anyway, maybe I'm wrong and I just have to sleep and wake up to realize it. Thanks for your time :) – elkolotfi Dec 04 '18 at 14:45
  • 13
    I'm marking this for re-open. It is not a simple matter of typing in 'php ??' or anything similar in the search box to find the answer. Even now, with this question 'php' and '??' will not display this question. I recommend editing the title to include '??' so it is easier for others to find. Second, @epixilog, marking a question as duplicate is in no way a reflection on you. Even if it's closed, it worked as intended as you found your answer. It's marked that way to ensure we keep all the information together, not to judge people asking questions. – Andrew T Finnell Dec 04 '18 at 19:50
  • 7
    @AndrewTFinnell It's not duplicate mention that bothers me actually it's the -5 feedback I got for my question ;( – elkolotfi Dec 05 '18 at 08:22
  • 37
    I upvoted because I also googled for „PHP double questionmark“. This is the first result and answers perfectly. – Zim84 Mar 20 '19 at 19:42
  • 11
    Same here exactly, thanks to this question I just found within less than 10 seconds what ?? means in PHP by literally typing "php double question mark operator" and confirming what I thought it would be. Excellent – kon Mar 21 '19 at 12:44
  • 3
    My search for "php double question mark" lead me here; now if only I knew it was called "the coalescing operator" being such an obvious term... Upvoted. Maybe if could be called the Muddy Waters operator, you know, to parallel the Elvis operator ?: – Jon Jul 10 '20 at 03:33

3 Answers3

568

It's the "null coalescing operator", added in php 7.0. The definition of how it works is:

It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.

So it's actually just isset() in a handy operator.

Those two are equivalent1:

$foo = $bar ?? 'something';
$foo = isset($bar) ? $bar : 'something';

Documentation: http://php.net/manual/en/language.operators.comparison.php#language.operators.comparison.coalesce

In the list of new PHP7 features: http://php.net/manual/en/migration70.new-features.php#migration70.new-features.null-coalesce-op

And original RFC https://wiki.php.net/rfc/isset_ternary


EDIT: As this answer gets a lot of views, little clarification:

1There is a difference: In case of ??, the first expression is evaluated only once, as opposed to ? :, where the expression is first evaluated in the condition section, then the second time in the "answer" section.

robsch
  • 9,358
  • 9
  • 63
  • 104
michalhosna
  • 7,327
  • 3
  • 21
  • 40
  • $foo = isset($y++) ? $y++ : 'something'; This doesn't work. Can not use isset on the result of an expression. – ascsoftw Sep 04 '19 at 12:45
  • @ascsoftw sorry, removed until i find of better example – michalhosna Sep 05 '19 at 20:25
  • 1
    Regarding the last edit : the number of times it gets evaluated also depends on the internal implementation of the ?? operator (is it really once?) – Tomek Jan 10 '20 at 10:37
  • 3
    +1 for the documentation link. I end up here every now and then because the operator has to be spelled out for Google to treat it as a search term, but all I really want is to read the docs ;) – ksadowski Mar 04 '20 at 14:36
  • 2
    Last edit is not very clear/concise. I had hard time reading and understanding it. Found this which clears what you wanted to say there. So please add an example. https://www.php.net/manual/en/language.operators.logical.php#115208 $a = (fruit(1) ? fruit(1) : 'apple');//fruit() will be called twice! – Valentin Apr 03 '20 at 07:13
  • Note that, like with `isset()`, this also works on `undefined` (e.g. typed class properties that have not been inialized yet). – Michiel Bakker Sep 18 '20 at 09:02
  • 1
    The edit is really unnecessary and confusing. The syntax for `a??b`, `a?:b`, and `a?a:b` all clear enough that only the last one has duplicate evaluation – Semra May 15 '21 at 15:56
  • so does `$value = $value ?? null;` means something? (A line from google cloud api source code) – AaA Aug 30 '21 at 04:23
  • @AaA I covers the case where the variable `$value` did not exist at all. – michalhosna Aug 30 '21 at 11:50
  • Can someone define "coalescing"?! :) – Jono Oct 18 '22 at 08:56
46
$myVar = $someVar ?? 42;

Is equivalent to :

$myVar = isset($someVar) ? $someVar : 42;

For constants, the behaviour is the same when using a constant that already exists :

define("FOO", "bar");
define("BAR", null);

$MyVar = FOO ?? "42";
$MyVar2 = BAR ?? "42";

echo $MyVar . PHP_EOL;  // bar
echo $MyVar2 . PHP_EOL; // 42

However, for constants that don't exist, this is different :

$MyVar3 = IDONTEXIST ?? "42"; // Raises a warning
echo $MyVar3 . PHP_EOL;       // IDONTEXIST

Warning: Use of undefined constant IDONTEXIST - assumed 'IDONTEXIST' (this will throw an Error in a future version of PHP)

Php will convert the non-existing constant to a string.

You can use constant("ConstantName") that returns the value of the constant or null if the constant doesn't exist, but it will still raise a warning. You can prepended the function with the error control operator @ to ignore the warning message :

$myVar = @constant("IDONTEXIST") ?? "42"; // No warning displayed anymore
echo $myVar . PHP_EOL; // 42
Cid
  • 14,968
  • 4
  • 30
  • 45
  • if(($_SESSION['captchaReq']++??$_SESSION['captchaReq']=0)<3) { } – Kamil Dąbrowski Dec 16 '21 at 05:34
  • @KamilDąbrowski yes? What's this? – Cid Dec 16 '21 at 07:28
  • If you can't, don't bother with shortening code. A code you can read and maintain easily is way better than something short – Cid Dec 17 '21 at 13:16
  • $_SESSION['req']++??$_SESSION['req']=0 is easy to read take advantage of new technologies – Kamil Dąbrowski Dec 26 '21 at 17:54
  • well, you can't do `null++`, so doing `$_SESSION['req']++??` makes no sense – Cid Dec 26 '21 at 18:20
  • you don't understand code is not null is 0 as begin initial any variable read again this ---> $_SESSION['req']++??$_SESSION['req']=0 You can image a lot think todo with the construction of logick avaiable from php 7> $hitCache++??$hitCache=0; it is post – Kamil Dąbrowski Dec 27 '21 at 20:08
  • What the point of using a null coalescing operator on something that can't be `null`? – Cid Dec 28 '21 at 07:22
  • Just a side note: Using @ in PHP is terrible practice and should never be done in production environments. I'm not sure any acceptable answer should encourage using it. – Jeffrey Van Alstine Aug 11 '22 at 15:47
21
$x = $y ?? 'dev'

is short hand for x = y if y is set, otherwise x = 'dev'

There is also

$x = $y =="SOMETHING" ? 10 : 20

meaning if y equals 'SOMETHING' then x = 10, otherwise x = 20

Prodigle
  • 1,757
  • 12
  • 23