12

I have an interface that declares the implementation needs methods such as find, findOrFail etc, basically Laravel eloquent methods.

I declare these methods in the interface because not everything that implements the interface will extend eloquent so I declare them in the interface so my app always knows the methods are going to be there.

What I want to know is, other than having a bunch of public function find($id){return parent::find($id)} type methods in the models that do extend the eloquent model is there an easy way to let the interface know that the method is handled via __call?

Hailwood
  • 79,753
  • 103
  • 257
  • 412

2 Answers2

10

Although there may be a larger question as to the cleanliness of such a design, you can accomplish something akin to this by using a trait which implements the methods of the interface:

interface FindableContract {
    public function find($id);
}

trait MagicFindableTrait {
    public function find($id) {
        return static::__call(__FUNCTION__, func_get_args()); 
    }
}

class MagicalParent {
    public function __call($method, $args) {
        if ($method == 'find') {
            return "User " . $args[0] . " is a witch! May we burn her?!";
        }
    }
}

class User extends MagicalParent implements FindableContract {
    use MagicFindableTrait;
}

class NonmagicalUser implements FindableContract {
    public function find($id) {
        return "User $id was found to be non-magical.  Let's burn him anyway.";
    }
}

print (new User)->find(123);
print (new NonmagicalUser)->find(321);
patstuart
  • 1,870
  • 17
  • 29
Gabriel
  • 570
  • 4
  • 13
  • 2
    In the end I decided to upvote, because I think it is really clever. I hesitated for a while because I think it is really clever. – Dennis Haarbrink Oct 06 '16 at 06:29
  • 1
    I agree Dennis, this is generally speaking a very bad idea. The primary use for something like this is academic/curiosity/cuteness. It probably shouldn't be used in real-world code. – Gabriel Oct 12 '16 at 07:46
  • In class User `use FindableTrait` should be `use MagicFindableTrait` – Manuel Jun 28 '18 at 16:42
3

No this will not work. While __call() is really nice for a dynamic coding style it's disadvantages are that you cannot enforce the signatures of the dynamic methods in an interface and you won't get an automated documentation for it.

But I think if you are at a point where you want to create an interface for those methods, there should be no need to use __call() anymore. I would just hardcode the methods.

hek2mgl
  • 133,888
  • 21
  • 210
  • 235
  • Seems that you have a design problem. Would like to help more but the question is a little bit vague. Could you show a basic example? – hek2mgl Jun 24 '13 at 02:15