Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return false when chaining methods

I have a validation class which uses method chaining. I would like to be able to do single checks with TRUE/FALSE like this:

if ($obj->checkSomething()) {}

But also chain methods like this:

if ($obj->checkSomething()->checkSomethingElse()) {}

The problem however is that if one method returns FALSE, it will not send back an object and thus breaks the method chaining which ends with this error:

Fatal error: Call to a member function checkSomething() on a non-object in ...

Do I have to pick either single method return calls or method chaining or is there a workaround?

like image 626
Seralize Avatar asked Jan 19 '23 10:01

Seralize


2 Answers

One idea would be to set an internal flag to indicate success or failure, and access it via another method, while checking that flag in each method and not doing anything if it's set. E.g.:

class A {
    private $valid = true;

    public function check1() {
        if (!$this->valid) {
            return $this;
        }
        if (!/* do actual checking here */) {
            $this->valid = false;
        }
        return $this;
    }
    public function check2() {
        if (!$this->valid) {
            return $this;
        }
        if (!/* do actual checking here */) {
            $this->valid = false;
        }
        return $this;
    }
    public function isValid() {
        return $this->valid;
    }
}

// usage:

$a = new A();

if (!$a->check1()->check2()->isValid()) {
    echo "error";
}

To minimize the boilerplate checking in each function, you could also use the magic method __call(). E.g.:

class A {
    private $valid;
    public function __call($name, $args) {
        if ($this->valid) {
            $this->valid = call_user_func_array("do" . $name, $args);
        }
        return $this;
    }
    private function docheck1() {
        return /* do actual checking here, return true or false */;
    }
    private function docheck2() {
        return /* do actual checking here, return true or false */;
    }
    public isValid() {
        return $this->valid;
    }    
}

The usage would be same as above:

$a = new A();

if (!$a->check1()->check2()->isValid()) {
    echo "error";
}
like image 138
JRL Avatar answered Jan 28 '23 15:01

JRL


I believe you're looking to have an instance evaluate as true/false based on the outcome of validation.

While some languages allow you to override the boolean value of an instance, php does not (except for casting to string, that is. See PHP's Magic Methods).

Also, the booleans page in the PHP Manual has a list of things that evaluate to false, but it doesn't give any method of overriding the behavior either.

That being said, I'd suggest going with JRL's idea, and construct a chain of validation rules, then 'execute' it with a function that returns the boolean needed in your if statement.

like image 35
Adam Wagner Avatar answered Jan 28 '23 13:01

Adam Wagner