80

Is there a way to test a range without doing this redundant code:

if ($int>$min && $int<$max)

?

Like a function:

function testRange($int,$min,$max){
    return ($min<$int && $int<$max);
}

usage:

if (testRange($int,$min,$max)) 

?

Does PHP have such built-in function? Or any other way to do it?

dynamic
  • 46,985
  • 55
  • 154
  • 231
  • 9
    There is a horrible way using `in_array()` and `range()`. Other than that, I don't think there is one – Pekka Feb 17 '11 at 13:17
  • 8
    Why would you call that "redundant code" ? It is what has to be evaluated, isn't it? – Nanne Feb 17 '11 at 13:19
  • @Pekka - agreed, not resource friendly, but *is* another option. :) – TNC Feb 17 '11 at 13:21
  • 3
    Indeed. Which bit of that original fast, readable code is redundant, exactly? And who would know just reading a call to your testRange() whether testRange(1, 1, 2) would be true or false? – Matt Gibson Feb 17 '11 at 13:23
  • 4
    I think what he's referring to is having to specify the same variable in the condition twice. While I agree that a language construct that lets you say `if($int between $min and $max)` would be nice, I'm afraid the only language I've seen do that is SQL. – Wes P Feb 17 '11 at 13:26
  • Is of course redundant because in the if you have to type twice the same var name ($int) introducing more possibilities to make errors, and more changes in case of refactor (@wes p: you are exactly right). and @anyonoums downvoter: explain in the comment why you are downvoting this simple question. – dynamic Feb 17 '11 at 13:27
  • @Wes P, would `$int between $min and $max` be the same as `$int > $min && $int < $max`, `$int >= $min && $int < $max`, `$int > $min && $int <= $max` or `$int >= $min && $int <= $max`? – binaryLV Feb 17 '11 at 13:29
  • 2
    @Yes Personally, I'd argue that using a function introduces more possibilities to make errors -- there's chance of getting your parameters in the wrong order, for example. Plus, would you want to add another function, to compare ($int >= $min && $int <= $max), another very common comparison? I suppose if you're writing this particular code over and over again, a function is the way to go if you don't mind the overhead, but yes, you'll have to roll your own, as there's not one built-in in PHP. (I am not, by the way, the anonymous downvoter, though, just interested in talking things over ;) ) – Matt Gibson Feb 17 '11 at 13:34
  • @yes123, for a language to have such operator, it should be clearly stated what it does. E.g., Wes P mentioned SQL which has `expr between min and max` operator, but it works differently from what you're looking for, so even if PHP had it, it would not work for you in this particular case. – binaryLV Feb 17 '11 at 13:37
  • 1
    @WesP: Also Python: `if 5 – Tometzky Sep 11 '14 at 08:13
  • Similar: [How to check if an integer is within a range of numbers in PHP?](http://stackoverflow.com/q/4684023/55075) – kenorb Mar 12 '15 at 18:43
  • Ideally, what I would like (and am disappointed that it's lacking in pretty much every language I've encountered) is a language construct that mimics mathematics in this regard. `$x > 0 && $x < 10` => `0 < $x < 10` – xiix Mar 30 '16 at 06:40
  • I think you need `>=` and `<=` for checking a range. Then `testRange(0, 0, 100) == true` – Nick Shvelidze Jun 27 '16 at 09:33

10 Answers10

104

Tested your 3 ways with a 1000000-times-loop.

t1_test1: ($val >= $min && $val <= $max): 0.3823 ms

t2_test2: (in_array($val, range($min, $max)): 9.3301 ms

t3_test3: (max(min($var, $max), $min) == $val): 0.7272 ms

T1 was fastest, it was basicly this:

function t1($val, $min, $max) {
  return ($val >= $min && $val <= $max);
}
Mark Paspirgilis
  • 1,180
  • 2
  • 8
  • 2
  • That's what I expected :) – alex Oct 09 '14 at 23:04
  • 1
    Nice! as i need it to tell me whether true or false, i added the following: `function t1($val, $min, $max) { if ($val >= $min && $val <= $max) {return true;} else {return false;} }` – Pathros Nov 17 '14 at 14:50
  • 13
    @pathros the above function already returns `true` or `false`, no need to write additional code – SBH Feb 27 '15 at 10:03
  • It's also unnecessary to use brackets. "return $val >= $min && $val <= $max;" is enough. – ElChupacabra Sep 30 '16 at 11:59
  • 2
    I don't think the question is asking about performance. Other languages have native operators for this and I think that's what OP was looking for. – Josh Johnson Feb 27 '17 at 16:08
  • Another test with this variant (filter_var) would still be interesting: https://stackoverflow.com/questions/4684023/how-to-check-if-an-integer-is-within-a-range-of-numbers-in-php – jMike Jan 22 '19 at 10:26
48

I don't think you'll get a better way than your function.

It is clean, easy to follow and understand, and returns the result of the condition (no return (...) ? true : false mess).

alex
  • 479,566
  • 201
  • 878
  • 984
16

There is no builtin function, but you can easily achieve it by calling the functions min() and max() appropriately.

// Limit integer between 1 and 100000
$var = max(min($var, 100000), 1);
Lars Strojny
  • 667
  • 4
  • 11
  • 9
    This is very interesting. However, I wouldn't use it purely for the sake of readibility. – aalaap Jun 27 '16 at 11:05
  • The idea is really interesting as said above, but it's difficult to read and it calls two function that can be avoided. – Anthony Sep 18 '17 at 10:45
12

Most of the given examples assume that for the test range [$a..$b], $a <= $b, i.e. the range extremes are in lower - higher order and most assume that all are integer numbers.
But I needed a function to test if $n was between $a and $b, as described here:

Check if $n is between $a and $b even if:
    $a < $b  
    $a > $b
    $a = $b

All numbers can be real, not only integer.

There is an easy way to test.
I base the test it in the fact that ($n-$a) and ($n-$b) have different signs when $n is between $a and $b, and the same sign when $n is outside the $a..$b range.
This function is valid for testing increasing, decreasing, positive and negative numbers, not limited to test only integer numbers.

function between($n, $a, $b)
{
    return (($a==$n)&&($b==$n))? true : ($n-$a)*($n-$b)<0;
}
Luis Rosety
  • 396
  • 4
  • 10
  • 2
    This is nice. Do note that if there's a chance that $n, $a and $b happen to be the same number, this function will return false while most others would return true. – bksunday Feb 06 '15 at 00:26
  • 1
    Thanks @bksunday for your comment. I have added treatment of this case to the code. – Luis Rosety May 19 '15 at 09:27
  • I have to add a precision to @bksunday comment and my answer. Interval can be open interval or closed interval. Open intervals don't include limits while closed ones do include them. As a consequence, in the case of the original question from dynamic, it was an open interval and therefore when $a=$b=$n it should return false as it was my original function, or even easier: An open interval ($a, $b) with $a=$b is an empty set. – Luis Rosety Mar 14 '18 at 08:15
  • if $n=0, and $a=0 and $b=1, this functionjs returns FALSE. Why? 0 is in range (between 0 and 1), so should return TRUE – Tikky Mar 01 '19 at 08:12
9

I'm not able to comment (not enough reputation) so I'll amend Luis Rosety's answer here:

function between($n, $a, $b) {
    return ($n-$a)*($n-$b) <= 0;
}

This function works also in cases where n == a or n == b.

Proof: Let n belong to range [a,b], where [a,b] is a subset of real numbers.

Now a <= n <= b. Then n-a >= 0 and n-b <= 0. That means that (n-a)*(n-b) <= 0.

Case b <= n <= a works similarly.

Esa Lindqvist
  • 311
  • 2
  • 6
  • Interval type (open or closed) is important. Open interval exclude limits while closed one do include limits. Please refer to https://en.wikipedia.org/wiki/Interval_(mathematics) – Luis Rosety Mar 14 '18 at 08:31
  • Well sure, when working with floating-point numbers, but when working with integers (as per the question) that's irrelevant. Keep in mind that (a,b) is effectively [a+1, b-1] with all integers a and b. – Esa Lindqvist Mar 15 '18 at 10:52
  • best answer for me – Tikky Mar 01 '19 at 08:12
3

There's filter_var() as well and it's the native function which checks range. It doesn't give exactly what you want (never returns true), but with "cheat" we can change it.

I don't think it's a good code as for readability, but I show it's as a possibility:

return (filter_var($someNumber, FILTER_VALIDATE_INT, ['options' => ['min_range' => $min, 'max_range' => $max]]) !== false)

Just fill $someNumber, $min and $max. filter_var with that filter returns either boolean false when number is outside range or the number itself when it's within range. The expression (!== false) makes function return true, when number is within range.

If you want to shorten it somehow, remember about type casting. If you would use != it would be false for number 0 within range -5; +5 (while it should be true). The same would happen if you would use type casting ((bool)).

// EXAMPLE OF WRONG USE, GIVES WRONG RESULTS WITH "0"
(bool)filter_var($someNumber, FILTER_VALIDATE_INT, ['options' => ['min_range' => $min, 'max_range' => $max]])
if (filter_var($someNumber, FILTER_VALIDATE_INT, ['options' => ['min_range' => $min, 'max_range' => $max]])) ...

Imagine that (from other answer):

if(in_array($userScore, range(-5, 5))) echo 'your score is correct'; else echo 'incorrect, enter again';

If user would write empty value ($userScore = '') it would be correct, as in_array is set here for default, non-strict more and that means that range creates 0 as well, and '' == 0 (non-strict), but '' !== 0 (if you would use strict mode). It's easy to miss such things and that's why I wrote a bit about that. I was learned that strict operators are default, and programmer could use non-strict only in special cases. I think it's a good lesson. Most examples here would fail in some cases because non-strict checking.

Still I like filter_var and you can use above (or below if I'd got so "upped" ;)) functions and make your own callback which you would use as FILTER_CALLBACK filter. You could return bool or even add openRange parameter. And other good point: you can use other functions, e.g. checking range of every number of array or POST/GET values. That's really powerful tool.

Krzysiu
  • 159
  • 9
3

You could do it using in_array() combined with range()

if (in_array($value, range($min, $max))) {
    // Value is in range
}

Note As has been pointed out in the comments however, this is not exactly a great solution if you are focussed on performance. Generating an array (escpecially with larger ranges) will slow down the execution.

Peter
  • 8,776
  • 6
  • 62
  • 95
2

Using comparison operators is way, way faster than calling any function. I'm not 100% sure if this exists, but I think it doesn't.

Thom Wiggers
  • 6,938
  • 1
  • 39
  • 65
  • Indeed using comparison operators is faster than calling a function, because functions are slow in PHP. On other hand, it's only one independant function that avoid to repeat the operators every time. A middle way could be Macro in some other languages like C, C++ or Rust. But PHP doesn't have this feature nor a built-in function 'between', so to use a function it's mandatory to create the function, or to use 'filter_var' as said in an answer even if in this case 'filter_var' is not very convenient to write. – Anthony Sep 18 '17 at 10:43
0

One possibility (not a solution) :

$mysqli->query("SELECT $value BETWEEN $min and $max as test")->fetch_object()->test;
Ehsan Chavoshi
  • 681
  • 6
  • 10
  • If you use this, please be aware that it is IMPERATIVE that you check `$value`, `$min` and `$max` for type. If one of them can be an arbitrary string (worst case from the user), this is an SQL injection hazard and you are gonna get hacked. – Matteo B. Oct 19 '22 at 15:10
0

This is an expansion on the answer provided by @Mark Paspirgilis, allows for selectable inclusion and returns a Boolean response.

public function between($p_value, $p_min, $p_max, $p_inclusive=0) {
  ## 0 = all inclusive; -1 = left inclusive; 1 = right inclusive
  if ($p_inclusive == -1) {
    return (bool)($p_value >= $p_min && $p_value < $p_max);
  }
  else if ($p_inclusive == 1) {
    return (bool)($p_value > $p_min && $p_value <= $p_max);
  }
  else {
    return (bool)($p_value >= $p_min && $p_value <= $p_max);
  }
} # END FUNCTION between
DanimalReks
  • 315
  • 4
  • 12