Decorator Pattern With Laravel Decorator Mode

Keywords: PHP Laravel Google

Decorator Pattern s Decorator Model

Outline:

 1. A beginner's doubts
 
 2. Characteristics of Decorator Model
 
 3. Simple case Masters Decorator Mode
 
 4. Application of Decorator Mode in Laravel

Confusing:
Before I started to study the source code of laravel, I knew little about Decorator Mode, but when I created a middleware, I still didn't understand how the $next closure in the middleware came in, so I google had a lot of blogs and blogs of my predecessors. In this article, I learned a lot of knowledge that I didn't know before, so I learned the principle of middleware loading, which benefited me a lot. Thank these predecessors for their selfless dedication. ok, back to the topic.

Characteristics of Decorator Model
I'll give you a detailed introduction.

"(1) Decorative objects and real objects have the same interface. In this way, client objects can interact with decorated objects in the same way as real objects.
(2) Decorative object contains a reference to a real object.
(3) Decorative objects accept all requests from clients. It forwards these requests to the real object.
(4) Decorative objects can add additional functions before or after forwarding these requests. This ensures that additional functions can be added externally without modifying the structure of a given object at runtime. In object-oriented design, the function extension of a given class is usually achieved through inheritance. From Baidu Encyclopedia

Simple case Masters Decorator Mode
Note: If you haven't been exposed to this model before, I suggest you read this article first. Decorator Model of Learning Notes in Key Technologies of laravel Framework Looking back on this article, the effect is better.
Well, if it's the first time to look at the decorator model and see the above feature "official elaboration", it's really a bit confusing. ok. In order to facilitate your quick understanding of the model, I wrote a case of "simplified version of laravel source code". Before putting the code, I'll tell you the most important thing to realize the model. It depends on two methods, as follows:

  1. call_user_func() Call me if you don't understand.

  2. array_reduce() You should see me.

Code:


    interface func{
        public static function handle($next);
    } 
    class beauty implements func{
        
        public static  function say($next){
            $next();
            echo "I don't think much of Diao silk.";
        }
    }

    class guy implements func{
        
            public static function say($next){
                    echo 'Once upon a time, a programmer wanted to find a girlfriend..';
                    $next();
                    
            }
    }

    $e=[guy::class,beauty::class];

    function getClosure(){
        
        return function ($a,$b){
            return function()use($a,$b){
                    $b::say($a);
            };
        };
    }

    $d = function(){ echo 'After searching for a long time, there was still no improvement. Suddenly, one day, I met my favorite goddess.,Result,Goddess said:'."\n";};

    call_user_func(array_reduce($e,getClosure(),$d));
   Don't worry about the code. Let the code run first and see what the result is. Then analyze the code.
   ok, in order to take care of new friends, I'll sort out the execution process for you.
   

Execution process:
First step.
First, the getClosure() function call returns a closure:

function($a,$b){
 return function()use($a,$b){
     return $b::say($a);
 }
}

Step two.
Take $d and $e[0] as the parameters of the first step to return the result and execute them to return the result:

function()use($a,$b){     
                     #At this point, $b="guy" 
                     #$a = D = function (){echo'has been looking for a long time, but it has not been any better. Suddenly one day, I met the goddess of my heart. As a result, the goddess said:'. "\ n;"
    return $b::say($a);
    }

Step 3.
The result of the second part and $e[1] are taken as the parameters of the first step to return the result and executed to return the result:

    function()use($a,$b){    
                      #At this point, $b= "beauty" $a='Step 2 returns the result' 
                      #      $a = function()use($,'beacuty'){
                      #        beauty::say(function()use('guy',$d){
                      #          return guy::say($d);
                      #       })
                      #     }
    return $b::say($a);
    }
   

Step 4. The closure returned by calling_user_func() calling array_reduce() is the result of step 3.
Beauty:: say ($d) => D () = > echo'There was a programmer who wanted to find a girlfriend before.'; = > echo'',''After looking for a long time, it hasn't been any improvement yet. Suddenly one day, she met the goddess of her heart, and she said:'=>'I can't see Daisy'.

The execution process is similar to that shown in the figure (carefully, like an onion, infiltrating from the outermost layer to the innermost layer, and then from the innermost layer to the outermost layer):

Application of Decorator Mode in laravel
The source code of laravel framework is given here for comparative analysis.

file index.php  line 50

    $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
    
    $response = $kernel->handle(
        $request = Illuminate\Http\Request::capture()
);

//File Illuminate Foundation Http Kernel. PHP
  

     public function handle($request)
        {
            try {
                $request->enableHttpMethodParameterOverride();
    
                $response = $this->sendRequestThroughRouter($request);
            } catch (Exception $e) {
             ....Eliminate exception handling
            }
    
            $this->app['events']->fire('kernel.handled', [$request, $response]);
    
            return $response;
        }
    
    
       protected function sendRequestThroughRouter($request)
       {
        $this->app->instance('request', $request);
    
        Facade::clearResolvedInstance('request');
    
        $this->bootstrap();
    
        return (new Pipeline($this->app))
                    ->send($request)
                    ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                    ->then($this->dispatchToRouter());
     }
    
    protected function dispatchToRouter()
    {
        return function ($request) {
            $this->app->instance('request', $request);
    
            return $this->router->dispatch($request);
        };
    }

//File IlluminatePipeLinePipeLine.php

       public function send($passable)
        {
            $this->passable = $passable;
    
            return $this;
        }
          public function through($pipes)
        {
            $this->pipes = is_array($pipes) ? $pipes : func_get_args();
    
            return $this;
        }
         public function then(Closure $destination)
    {
        $firstSlice = $this->getInitialSlice($destination);

        $pipes = array_reverse($this->pipes);

        return call_user_func(
            array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable
        );
    }
        protected function getInitialSlice(Closure $destination)
    {
        return function ($passable) use ($destination) {
            return call_user_func($destination, $passable);
        };
    }

    protected function getSlice()
    {
        return function ($stack, $pipe) {
            return function ($passable) use ($stack, $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.
                if ($pipe instanceof Closure) {
                    return call_user_func($pipe, $passable, $stack);
                } else {
                    list($name, $parameters) = $this->parsePipeString($pipe);
    
                    return call_user_func_array([$this->container->make($name), $this->method],
                            array_merge([$passable, $stack], $parameters));
                }
            };
        };
    }

//File IlluminateFoundationApplication.php 

       public function shouldSkipMiddleware()
        {
            return $this->bound('middleware.disable') &&
                   $this->make('middleware.disable') === true;
        }

Posted by kratos-2012 on Thu, 11 Jul 2019 11:32:39 -0700