优雅的方式在两个价格之间获得最小值,同时抛弃非正值

Currently, I'm doing this in several steps, and I wonder if there's a better way.

Here's how I'm doing it.

  1. Check if the values are both non-numeric or both non-positive numbers. If they are, throw an error and exit. This guarantees at least 1 positive number.
  2. Cast both values to (float). If one of the two was non-numeric, it should be 0 now.
  3. If num1 is zero, use num2. Else If num2 is zero, use num1. Else use min(num1,num2)

// 1
if(!(is_numeric($num1) && $num1 >0) && !(is_numeric($num2) && $num2 >0) ) {
    die('error');
}
// at least one is a positive number. Other could be a different number or not numeric.

// 2
$num1 = (float)$num1;
$num2 = (float)$num2;
// now both are numbers, at least one is positive

// 3
if($num1 <= 0) {
    $price = $num2;
} elseif($num2 <= 0) {
    $price = $num1;
} else {
    $price = min($num1,$num2);
}
// finally we have the price

I am using php5

I recommend that you convert the numbers to floats before comparing them to 0; this will force non-numerics to 0 and then you can filter out the negatives, the original zeros, and the converted zeros in one step. If there are no qualifying prices, make an early return. If at least one qualifying price exists, return the lower of the two.

As a matter of convenient, simplified, DRY programming, I am batching the values into an array for swift handling.

Code: (Demo)

function newGetMinPrice($nums) {
    $nums = array_filter($nums, function($v){ return (float)$v > 0;});  // convert to float and check if greater than 0
    if (empty($nums)) {
        return 'error';  // if no qualifying prices, return error
    }
    return min($nums);  // return the lowest qualifying price
}

$tests = [[0, .1], [1, 'foo'], [.24, -.25], [3, 3], ['foo', 'bar'], [-0, 0.1], [90, -90], [0, 0], [1, 1]];
foreach ($tests as $test) {
    echo "new: {$test[0]} -vs- {$test[1]} = ",newGetMinPrice($test), "
";
}

Output: (identical performance as your posted snippet

new: 0 -vs- 0.1 = 0.1
new: 1 -vs- foo = 1
new: 0.24 -vs- -0.25 = 0.24
new: 3 -vs- 3 = 3
new: foo -vs- bar = error
new: 0 -vs- 0.1 = 0.1
new: 90 -vs- -90 = 90
new: 0 -vs- 0 = error
new: 1 -vs- 1 = 1

...or you could condense like:

$nums = array_filter($nums, function($v){ return (float)$v > 0;});  // convert to float and check if greater than 0
return empty($nums) ? 'error' : min($nums);

p.s. you could also generate a battery of conditions if you don't want to use array_filter() ...though I don't think it is any prettier than your original snippet.

$num1 = max(0, (float)$num1);
$num2 = max(0, (float)$num2);
if ($num1 === 0) {                    // bad num1
    if ($num2 === 0) {                // bad num2
        return 'error';              // send error
    }
    return $num2;                    // send good num2
}
// 1 is good...
if ($num2 === 0 || $num1 <= $num2) {  // bad num2 or num1 better than num2
    return $num1;                    // send good/better num1
}
return $num2;                        // both num1 and num2 are good, send num2

or without declaring newGetMinPrice():

$nums = array((float)$num1,(float)$num2);  // force input values to float values
$nums = array_filter($nums, function($v){return $v > 0;});  // check if greater than 0
if (empty($nums)) {
    die('error');
} else {
    $price = min($nums);  // declare lowest qualifying price
}

Demo