UXerUIer
UXerUIer

Reputation: 2338

Returning true/false in functions with a message to further explain the reason why it returned false

I'm creating functions where I want to be able to output true or false pertaining to if statements within the function are met. An example of this is like this:

function pokeme($number){
    if($number > 10)
    {
        return true;
    }
    else
    {
        return false;
    }
}

However, one problem with this approach is that if the function returns false, you wont be able to decipher which false means what, especially if there is more than one if/else statements.

My question is, how do I output a false plus a way to later identify what that false was?

Do I do an array?

return array("false", "message pertaining to whatever");

However, if that is done, you can't really do this, plus...:

if(pokeme()){ /*success*/ } else { /*there may be multiple falses for different situations... how do I distinguish what it is? */}

Upvotes: 0

Views: 2117

Answers (3)

Your Common Sense
Your Common Sense

Reputation: 157828

That's one of those questions, which, being very poorly phrased, lead to completely wrong answers.

Before asking such a question, one has to realize that there are two kinds of functions:

  • functions that perform some action
  • functions that do nothing but just verify the parameter, telling whether it's right or wrong

And the approach for these two kinds must be completely different.

In case pokeme() function has to use the $number parameter somehow, but for some reason cannot do that, then an exception must be thrown. Because it's the very purpose for exceptions: to handle the exceptional behavior. In this case, the function will never returns false, so it makes no sense to return true either. So it will be either the correct result or exception will be thrown. But it is important to understand that as a rule, exceptions shouldn't be caught on the spot. Least an exception has to be used to convey some message from a function.

An exception should be used only if a function is unable to do its job:

function divide_by($number, $divisor)
{
    if (!is_numeric($number) || !is_numeric($divisor)) {
        throw new InvalidArgumentException("The arguments must be nubmers");
    }
    if ($divisor === 0) {
        throw new InvalidArgumentException("Cannot divide by zero");
    }
    return $number / $divisor;
}

In case pokeme() function, as it shown in the example provided, has to test the $number somehow, and tell if it's all right or not, no exceptions have to be used. Because wrong value is not an exceptional case.

Here, the simplest approach to convey the message would be to reverse the function's "polarity" and make it return false in case the parameter is all right, and a true-ish value in case it's wrong. Which will allow us to return the very message we need.

function check_number($number)
{
    if(!is_int($number))
    {
        return "The value provided is not numeric";
    }
    if($number < 10)
    {
        return "The number is less than 10";
    }
    return false;
}

and then it can be used like this

$error = check_number($number);
if(!$error) {
    /*success*/ 
} else {
    $errors[] = $error;
}

But this approach is rather silly. A more robust solution would be to write a class, utilizing such a handy feature as class variables

class NumberValidator
{
    protected $error;
    public function validate()
    {
        if(!is_numeric($number))
        {
            $this->error = "The value provided is not numeric";
            return false;
        }
        if($number < 10)
        {
            $this->error = "The number is less than 10";
            return false;
        }
        return true;
    }
    public function getError()
    {
        return $this->error;
    }
} 

and then it can be used like this

$validator = new NumberValidator();
if($validator->validate($number)) {
    /*success*/ 
} else {
    $errors[] = $validator->getError();
}

Upvotes: -1

fabpico
fabpico

Reputation: 2917

For fully automated input validations you can make use of the Symfony form component, and its Validation. You can also add very simple constraints like LessThan(10) exactly like in your example, and the component automatically writes the appropriate error message back to your page (and the invalid form e.g. dont performs DB inserting). It exists a lot of prepared constraints to use, you can also create own ones.

Or if you want to write all by your self, i suggest you to read OOP and Exception handling before.

EDIT

If you want to "collect" errors with its messages, solving this procedural for your code example (not recommended) you can store this messages in a temporary array in the superglobal variable $_SESSION. I explicitly say superglobal variable. Dont use a global variable and inject it with the global key, this will become very complex code in long therm.

Anyway my idea using $_SESSION. This code works for me:

<?php
session_start();

// Resetting the tmp session array on every page reload. That previous error messages are resetted.
$_SESSION['errors'] = array();

function printSessionErrors()
{
    // Print errors stored in the session if some exists
    if (array_key_exists('errors', $_SESSION)) {
        foreach ($_SESSION['errors'] as $i => $error) {
            $success = true === $error['success'] ? 'true' : 'false'; // Only for print
            $message = $error['message'];
            echo "Success: $success. Message: $message <br>";
        }
    }
}

function pokeme($number)
{
    $expected = 10;
    $success = null;

    if ($number > $expected) {
        $success = true;
    } else {
        $_SESSION['errors'][] = array(
            'success' => $success,
            'message' => "Number $number is less than $expected"
        );
        $success = false;
    }

    return $success;
}

pokeme(1);
pokeme(7);
pokeme(99);
printSessionErrors();

Now depending on if it was a form POST or procedural validation you add printCleanSessionErrors() on top (after session_start()) or on bottom on the code.

I get this output:

Success: false. Message: Number 1 is less than 10 
Success: false. Message: Number 7 is less than 10 

You only have to add the $_SESSION['errors'][] = array .... into your other error situations.

Upvotes: 1

FirstOne
FirstOne

Reputation: 6217

Note that the way the idea is demonstrated here might not be the best, but once you get te hang of it, it gets easier. Also, read end note, please.

If you want to use like this (true is expected and false is problem):

if(pokeme()){ /*success*/ } else { /* not needed */}

You can do something like this:

function pokeme($number){
    //let's say you want to return true if it's >10 and -9 to -1
    if($number > 10){
        // do something
        return true;
    }
    if($number < 0 && $number > -10){
        return true;
    }
    // handling multiple problems (just 2 ^^)
    if($number < -9){
        throw new Exception("Invalid input. Can't use negative smaller than -9.");
    }

    throw new Exception('Invalid input. Expected bigger than 10.');
}

Two tests:

try{
    echo "RESULT1 :".pokeme(-42).":"; // not shown (error in this line)
    echo "RESULT2 :".pokeme(11).":"; // not shown
}catch(Exception $e){
    echo "Error: '".$e->getMessage()."'"; // Just the message
}

echo "<br><br>";

try{
    echo "RESULT3 :".pokeme(11).":<br>"; // shown
    echo "RESULT4 :".pokeme(10).":"; // not shown (error in this line)
}catch(Exception $e){
    echo $e; // Full error
}

You can use it like this:

try{
    if(pokeme(11)){
        echo "VALID INPUT<br>";
    }
    if(pokeme(5)){
        echo "I'm not seen :\\";
    }
}catch(Exception $e){
    echo "Error: '".$e->getMessage()."'";
}

End note: Think of this like you are using a built-in php function that might cause an error. This way you have to handle it with a try..catch.

More about Exceptions.

Upvotes: 1

Related Questions