5

With this test page:

$page   = (int) $_GET['page'] ?: '1';
echo $page;

I don't understand the output I'm getting when page is undefined:

Request   Result
?page=2   2
?page=3   3
?page=    1
?         error: Undefined index page

Why the error message? It's PHP 5.3; why doesn't it echo "1"?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Isis
  • 4,608
  • 12
  • 39
  • 61
  • 5
    Pretty much unrelated, but you really want `1`, not `'1'`. – ThiefMaster Nov 17 '10 at 23:28
  • 1
    On the command line, this prints 1 just fine: `php -r 'echo (int)$foo ?: 1;'` (PHP 5.3.3, notice the lack of error due to error reporting being silent). Can you try to run that and see what it does? Does it really say "**error**, undefined index"? – deceze Nov 17 '10 at 23:33
  • 2
    It is and has always been a notice. That "error message" is certainly hand-written. – ThiefMaster Nov 17 '10 at 23:39

5 Answers5

12

The proper way (in my opinion) would be:

$page = isset($_GET['page']) ? (int) $_GET['page'] : 1;

Even if you used the new style, you would have problems with ?page=0 (as 0 evaluated to false). "New" is not always better... you have to know when to use it.

DisgruntledGoat
  • 70,219
  • 68
  • 205
  • 290
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Yeah.. the ?: operator is useless for that.. even though a "return expr1 if it is not unset/empty, otherwise expr2" operator would be awesome they never added that. – ThiefMaster Nov 17 '10 at 23:26
  • @Isis: See my answer for an explanation why you cannot use it. – ThiefMaster Nov 17 '10 at 23:28
  • I think you can also use `$page = $_GET['page'] || 1;` – Niet the Dark Absol Nov 17 '10 at 23:29
  • @Kolink No, PHP will return `true` or `false`, not the values of the operands. – deceze Nov 17 '10 at 23:31
  • Besides that, isset/empty are REQUIRED to not get an "undefined index" notice. – ThiefMaster Nov 17 '10 at 23:34
  • @Isis: You ***cannot*** do it with the new operator unless you don't care about an E_NOTICE warning - but you really should. – ThiefMaster Nov 17 '10 at 23:34
  • You really should have a tipjar for every unnecessary check like that. – AndreKR Nov 17 '10 at 23:37
  • 2
    The one who downvoted can at least explain *why*. @Isis: Yes, they are optional but they can make the code easier to read... – Felix Kling Nov 17 '10 at 23:44
  • if page=0 or page=-1 it will regard them as true .. Is there any way to do something to be considered correct only those numbers which are greater than 0? – Isis Nov 17 '10 at 23:44
  • 2
    @Isis: Just add another test: `(isset($_GET['page']) && $_GET['page'] > 0) ? $_GET['page'] : 1` (parenthesis looking pretty good now, eh? ;)) – Felix Kling Nov 17 '10 at 23:48
  • @Felix As you could imagine, I did. You may not share my opinion but there's an explanation in the comments of my answer. – AndreKR Nov 17 '10 at 23:49
  • @AndreKR: So you really think, my answer is not useful? You are right, I don't share your opinion, but down- and upvoting should be done from an objective and not subjective point of view. Btw I'd rather have one test too much as one too less and don't trust too much on type coercion. – Felix Kling Nov 17 '10 at 23:52
  • @AndreKR: Not to mention the semantical difference between `if($a['foo'])` and `if(isset($a['foo']))`. – Felix Kling Nov 17 '10 at 23:58
  • You are writing about "the proper way", so from my point of view your answer is plain wrong. As the community supports your answer, that one down vote won't harm you, will it? – AndreKR Nov 18 '10 at 00:00
  • I am aware of that difference and given that "page" is some kind of ID or something, for page=0 the correct (just my opinion) program flow would be to *not* take the action in the *if* branch. – AndreKR Nov 18 '10 at 00:03
  • @AndreKR: No, I don't care about it as such, only in the reason... if my first few words are worth a downvote for you, then so be it. – Felix Kling Nov 18 '10 at 00:04
  • @Felix Maybe I am not aware of the graveness of a downvote. I don't want to insult you personally. I just think that yours isn't a good answer (thus the downvote) because it leads to code that I consider bad code style. – AndreKR Nov 18 '10 at 00:07
  • @AndreKR: Whatever, nevermind. It is not a big deal. I just wanted to know why, I know it now, I would not do it the same way (but I hardly give downvotes anyway), but everyone is doing it the way one thinks is best. No hard feelings! :) – Felix Kling Nov 18 '10 at 00:11
  • @AndreKR Apparently you're the only one though. :o) – deceze Nov 18 '10 at 00:11
3

Unfortunately you cannot use it for the purpose you'd like to use it for:

Expression expr1 ?: expr3 returns expr1 if expr1 evaluates to TRUE, and expr3 otherwise.

So you'll still have to use isset or empty() - the ?: operator does not include an isset check. What you need to use is:

$page = !empty($_GET['page']) ? (int)$_GET['page'] : 1;
ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
3

Just for completeness, another way to achieve it is to pull operator rank:

 $page = (int)$_GET["page"]  or  $page = 1;

Many people perceive this as unreadable however, though it's shorter than isset() constructs.

Or if you are using input objects or any other utility class:

 $page = $_GET->int->default("page", 1);
mario
  • 144,265
  • 20
  • 237
  • 291
  • Your 1st example raises an error, if the `page` index doesn't exist, doesn't it? – DanMan Aug 13 '15 at 11:18
  • @DanMan It raises a *Notice*. – mario Aug 13 '15 at 11:23
  • Yes, that's what I meant. Thanks for clarifying. – DanMan Aug 13 '15 at 11:29
  • It also doesn't work the way you describe it: http://php.net/manual/en/language.operators.logical.php The part after the `or` is always ignored in the assignment. You'd need the null coalesce operator from PHP 7 for it to work. – DanMan Aug 13 '15 at 11:35
  • It's just two *assignment expressions* combined with an `or`. It's more or less `($a = 0) or ($a = 1);`. The second `or` expression is ignored when the first part isn't *falsy*. – mario Aug 13 '15 at 11:42
  • Right, I get it now. Thanks. I think I'm one of the "many people" though. ;) – DanMan Aug 13 '15 at 12:19
2

It's because you're trying to typecast something that's undefined: (int) $_GET['page']

Remove the (int) or set the typecast after the conditional line.

wajiw
  • 12,239
  • 17
  • 54
  • 73
  • Try doing this: $page = 1; if (!isset($_GET['page'])) { $page = (int) $_GET['page'] ?: '1'; } echo $page; – wajiw Nov 17 '10 at 23:25
1

If bloat is your concern, how about a helper function?

function get_or($index, $default) {
    return isset($_GET[$index]) ? $_GET[$index] : $default;
}

then you can just use:

$page = get_or('page', 1);

which is clean and handles undefined values.

Matteo Riva
  • 24,728
  • 12
  • 72
  • 104