major function
Record your actual call operation and call again where you want
Just like anonymous functions, temporary storage of your call operations is generally used for chain calls, and then it actually works on the object you want to operate on
It's like I didn't say it
Usage scenarios
If the laravel project uses the warehouse mode, then for more complex query conditions, there are generally three operations
- Add method for special query
- Set a rule, assemble the array according to the rule, and then implement the parsing in the warehouse class
- Pass anonymous function and write query conditions in anonymous function
Now you can optimize the third method by passing in a CallEcho object in the following code
//In the controller $callEcho = (new CallEcho())->where("username", "Jack Ma")->where("is_boss", 1)->first(); $fubao = (new UserRepository)->first($callEcho); //Warehouse class class UserRepository{ public function first(CallEcho $callEcho){ return $callEcho->invoke(new User()); } }
It looks like an anonymous function, but CallEcho can be inherited to implement some interfaces. After inheritance, you can also perform some operations on query conditions, such as filtering. With anonymous functions, it's entirely up to the conscience of the caller.
The most important thing is what face-to-face object is
Upper code
class CallEcho { protected $callable = null; public function __construct() { //callable initialization $this->seed(); } protected function seed(){ $this->callable = $this; } public function __invoke($obj) { return $obj; } public function __call($name, $arguments) { $current = $this->callable; /** * Every time a call is generated, wrap a layer on the callable */ $this->callable = function($obj) use($name, $arguments, $current){ return call_user_func_array($current, [$obj])->{$name}(...$arguments); }; return $this; } //Act on real objects public function invoke($obj){ return call_user_func_array($this->callable, [$obj]); } }
Simple testing and use
class TestCallEcho{ protected $called = []; public function __call($name, $arguments) { $this->called[] = [$name, $arguments]; return $this; } public function end(){ $this->called[] = "end"; return $this; } public function getCalled(){ return $this->called; } } function testArrayEq($array1, $array2){ if(count($array1) !== count($array2)){ return false; } foreach ($array1 as $index => $value1){ if(!isset($array2[$index])){ return false; } $value2 = $array2[$index]; if(is_array($value1) && is_array($value2)){ if(!testArrayEq($value1, $value2)){ return false; }else{ //Continue to judge } }else{ if($value1 !== $value2){ return false; } } } return true; } function testTestArrayEq(){ $array1 = [1, 2]; $array2 = [1, 3]; $array3 = [1, 2, 3]; assert(testArrayEq($array1, $array2) == false); assert(testArrayEq($array1, $array3) == false); assert(testArrayEq($array1, $array1) == true); } testTestArrayEq(); $obj = new \stdClass(); $callEcho = new CallEcho(); /*************Focus start****************/ /** @var CallEcho $callEcho */ $callEcho = $callEcho->testNumber(1)->testString("myname")->testObj($obj)->testMulti(1, "myname")->testMulti2("1", $obj)->end(); /** @var TestCallEcho $testCallEcho */ $testCallEcho = $callEcho->invoke(new TestCallEcho()); /************End of focus****************/ //It's basically the same thing $a = function($obj){ $obj->testNumber(1)->testString("myname")->testObj($obj)->testMulti(1, "myname")->testMulti2("1", $obj)->end(); }; $called = $testCallEcho->getCalled(); $eq = testArrayEq($called, [ ["testNumber", [1]], ["testString", ["myname"]], ["testObj", [$obj]], ["testMulti", [1, "myname"]], ["testMulti2", ["1", $obj]], "end" ]); assert($eq);
PS
Inspiration from Slim 3 Middleware Implementation