最近在研究laravel5.5的源代码,发现了其中的一段代码觉得挺有意思!
文件:vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php
public function then(Closure $destination) { $pipeline = array_reduce( array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination) ); return $pipeline($this->passable); }
protected function carry() { return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { if (is_callable($pipe)) { // If the pipe is an instance of a Closure, we will just call it directly but // otherwise we'll resolve the pipes out of the container and call it with // the appropriate method and arguments, returning the results back out. return $pipe($passable, $stack); } elseif (! is_object($pipe)) { list($name, $parameters) = $this->parsePipeString($pipe); // If the pipe is a string we will parse the string and resolve the class out // of the dependency injection container. We can then build a callable and // execute the pipe function giving in the parameters that are required. $pipe = $this->getContainer()->make($name); $parameters = array_merge([$passable, $stack], $parameters); } else { // If the pipe is already an object we'll just make a callable and pass it to // the pipe as-is. There is no need to do any extra parsing and formatting // since the object we're given was already a fully instantiated object. $parameters = [$passable, $stack]; } return method_exists($pipe, $this->method) ? $pipe->{$this->method}(...$parameters) : $pipe(...$parameters); }; }; }
此段代码初看上去让人很迷惑,特作以下demo分解:
//闭包与array_reduce结合测试 $a = array( 1 , 2 , 3 , 4 , 5 ); $b = array_reduce ( $a , function($v , $w){ return function($p) use($v, $w){ var_dump($v); }; } ); if(is_callable($b)){ $b('spring'); }
输出:
object(Closure)#5 (2) { ["static"]=> array(2) { ["v"]=> object(Closure)#4 (2) { ["static"]=> array(2) { ["v"]=> object(Closure)#3 (2) { ["static"]=> array(2) { ["v"]=> object(Closure)#2 (2) { ["static"]=> array(2) { ["v"]=> NULL ["w"]=> int(1) } ["parameter"]=> array(1) { ["$p"]=> string(10) "<required>" } } ["w"]=> int(2) } ["parameter"]=> array(1) { ["$p"]=> string(10) "<required>" } } ["w"]=> int(3) } ["parameter"]=> array(1) { ["$p"]=> string(10) "<required>" } } ["w"]=> int(4) } ["parameter"]=> array(1) { ["$p"]=> string(10) "<required>" } }