Using short circuiting to get first non-null variable
Asked Answered
P

8

25

What's the equivalent of the following (based in JS style) in PHP:

echo $post['story'] || $post['message'] || $post['name'];

So if story exists then post that; or if message exist post that, etc...

Predicant answered 20/11, 2011 at 18:44 Comment(4)
what's the point in such operator? Don't you know what certain variable you want to output?Gerson
For just 2 arguments you can use: echo isset($_POST['story']) ? $_POST['story'] : $_POST['message'];, eventually try to nest it.Ungainly
It's based on facebook api stream; only one/two of three will exist per post.Predicant
The page is not full of great advice. Many of the answers are performing loose comparisons and not strictly checking null-ness.George
D
42

It would be (PHP 5.3+):

echo $post['story'] ?: $post['message'] ?: $post['name'];

And for PHP 7:

echo $post['story'] ?? $post['message'] ?? $post['name'];
Dara answered 5/7, 2013 at 7:26 Comment(3)
This will generate a warning for variables which aren't setCollop
I am really surprised. I didn't know about this all these yearsFunke
The Elvis operator DOES NOT perform the same evaluation as the Null Coalescing operator. This answer is misleading.George
G
17

There is a one-liner for that, but it's not exactly shorter:

echo current(array_filter(array($post['story'], $post['message'], $post['name'])));

array_filter would return you all non-null entries from the list of alternatives. And current just gets the first entry from the filtered list.

Gnarly answered 20/11, 2011 at 18:52 Comment(6)
Runtimewise, this is going to wind up enumerating all of the values, null or not, right? The JS example would have stopped at the first non-null value.Enlistment
@pinouchon With all due respect, this is not hard to read at all. Although I like the answer from Kluska000 better.Apollonius
array_filter returns all the non-null entries from the array, not just the first one.Bullshit
@Bullshit That's why the current() wraps it.Gnarly
@Gnarly but your answer says "array_filter would return you the first non-null entry". It's wrong. array_filter returns ALL non-null entries, that's why current() is needed.Bullshit
LoOks a lot like https://mcmap.net/q/537879/-get-first-non-null-value-from-a-flat-arrayGeorge
M
6

Since both or and || do not return one of their operands that's not possible.

You could write a simple function for it though:

function firstset() {
    $args = func_get_args();
    foreach($args as $arg) {
        if($arg) return $arg;
    }
    return $args[-1];
}
Malorie answered 20/11, 2011 at 18:46 Comment(4)
Yea I figured this would be my other way, I was hoping there was an even shorter way of executing.Predicant
The easiest way would be switching e.g. to python :pMalorie
I think passing non-existing var to this function would cause error.Dara
@AdamPietrasiak -- I thought so too, but I just tested it and it doesn't complain. Though I wouldn't call it "firstset", but maybe "firsttrue".Merchantman
C
5

As of PHP 7, you can use the null coalescing operator:

The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.

// Coalescing can be chained: this will return the first
// defined value out of $_GET['user'], $_POST['user'], and
// 'nobody'.
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
Collop answered 25/2, 2016 at 8:53 Comment(2)
Now we just have to wait for PHP 7 hit production repos, super excited to use this.Predicant
This wouldn't work for the question as asked unless not all the fields even exist because it won't treat null strings (returned if a field is empty) as NULLs.Zygo
R
5

Building on Adam's answer, you could use the error control operator to help suppress the errors generated when the variables aren't set.

echo @$post['story'] ?: @$post['message'] ?: @$post['name'];

http://php.net/manual/en/language.operators.errorcontrol.php

Risner answered 10/3, 2016 at 23:22 Comment(0)
H
1

That syntax would echo 1 if any of these are set and not false, and 0 if not.

Here's a one line way of doing this which works and which can be extended for any number of options:

    echo isset($post['story']) ? $post['story'] : isset($post['message']) ? $post['message'] : $post['name'];

... pretty ugly though. Edit: Mario's is better than mine since it respects your chosen arbitrary order like this does, but unlike this, it doesn't keep getting uglier with each new option you add.

Hie answered 20/11, 2011 at 18:55 Comment(1)
But your option accounts for missing associative key that would generate a php error otherwise.Interlock
C
1

You can try it

<?php
    echo array_shift(array_values(array_filter($post)));
?>
Cauca answered 20/11, 2011 at 19:3 Comment(0)
P
1

Because variety is the spice of life:

echo key(array_intersect(array_flip($post), array('story', 'message', 'name')));
Pemba answered 21/11, 2011 at 1:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.