1

I'm building an application, and I need to be able to chain methods, so I will need to be able to call methods dynamically and statically.

For example:

$results = Class::where('something')
                ->where('something else');

In this case, the method 'where' needs to be called statically and dynamically, and still be allowed to be chained.

I know Laravel has something like this with Eloquent, but I do not know how to implement something like this.

4
  • more code please :) , anyways, if you want to do this you have to return your object from the where function Commented Mar 30, 2017 at 20:49
  • 1
    If you know Laravel does it, why not simply look at the Laravel code? Here's the relevant code Commented Mar 30, 2017 at 20:50
  • Laravel uses facades. Static call to a facade Class::where('something') returns an instance of another class on which ->where('something else'); is being called. As a side note, you misuse term 'called dynamically'. Commented Mar 30, 2017 at 20:51
  • he wants to implement this li ke Laravel, he's not using Laravel Commented Mar 30, 2017 at 20:51

2 Answers 2

2

I just surprised myself by proving that this is indeed possible:

<?php
class Test {
    private static $myself;
    public function do() {
        echo isset($this) ? 'd' : 's';
        if (!isset(self::$myself)) {
            self::$myself = new self;
        }
        return self::$myself;
    }
    public static function done() {
        echo PHP_EOL;
    }
}
Test::do()->do()->do()->done();
$myTest = new Test;
$myTest->do()->do()->do()->done();
$myTest::do()->do()->do()->done();
$myTest::do()->do()::do()->done();
Test::do()->do()->do()->done();

The output is:

sdd
ddd
sdd
sds
sdd

But it is unbelievable bad style in my eyes...

Sign up to request clarification or add additional context in comments.

12 Comments

it is Class::where('something') in the question. Not $class::where('something')
Sorry, I had to revise the answer, the former version only appeared to be working, fixed that. The credit goes to @Bamar and his answer here!
Since my answer presumably doesn't work for the same reason your original one didn't, I've deleted mine. You can have the rep for working out the winning combination.
Singleton all the DB classes!
@Sammitch Is that your general perspective of the world? Or does this have anything do to with this topic?
|
0

Just out of pure interest I've found a way to do this using __call and __callStatic and setting the methods you want to call to be inaccessible to the scope that is calling it (i.e. set the methods as private or protected).

Important warning: Using __call or __callStatic can lead to unexpected behavior! First read here to make sure you understand this. The code below dynamically executes the private class methods called from outside the class, so you need to be sure to whitelist specific methods that you want to add this behavior to. There may be other security issues that I have not dealt with, so use at your own risk.

class MethodTest
{

    private static $obj;
    private $fruit = 'watermelon';

    private function handleDynamicCallType($name, $arguments)
    {
        switch ($name) {
            case 'method1':
            case 'method2':
                $this->{$name}($arguments);
                break;
            default:
                throw new Exception("Invalid name");
        }
    }

    private function method1() {
        echo $this->fruit . ' ';
    }

    private function method2() {
        $arg_list = func_get_args();
        if (!empty($arg_list[0][0])) {
            $this->fruit = $arg_list[0][0];
        }
    }

    public function __call($name, $arguments)
    {
        $this->handleDynamicCallType($name, $arguments);
        return $this;
    }

    public static function __callStatic($name, $arguments)
    {
        if (!isset(self::$obj)) {
            self::getNewStaticInstance();
        }
        self::$obj->{$name}($arguments);
        return self::$obj;
    }

    public static function getNewStaticInstance()
    {
        self::$obj = new MethodTest();
        return self::$obj;
    }
}

$obj = new MethodTest;
$obj->method1()::method2('orange')->method1();
echo PHP_EOL;
MethodTest::method1()->method2('plum')::method1();

Output:

watermelon orange 
orange plum 

However the static object retains its properties after being called previously (notice the two orange strings). If this is undesired, we can force it to reset by calling getNewStaticInstance():

MethodTest::method1()::method2('plum')::method1()::getNewStaticInstance()::method1();

Output:

watermelon plum watermelon 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.