PHP Process for Processing WEB Requests

PHP, as the best programming voice in the world, is widely used in Web development.Because its grammar and C are similar, and it has a very smooth learning curve, more and more people are using PHP for the rapid development of Web products.Many development frameworks have emerged in the PHP world, such as Laravel, ThinkPHP, etc. However, no matter what the general framework is, they all follow the same pattern when processing Web requests. This paper first describes the basic framework for PHP to develop Web applications, and then separately analyzes the processing flow of Laravel and ThinkPHP when processing Web requests.

Basic Architecture for Developing Web Applications with PHP

When PHP develops Web applications, requests need to point to specific entry files.WebServer is a content distributor. When he accepts a user's request, if it is a static file such as css, js, etc., WebServer finds the file and sends it to the browser. If it is requesting / index.php, according to the configuration file, WebServer knows this is not a static file and needs to go to the PHP parserReally, he will simply process the request and hand it to the PHP parser.

WebServer sends the requested Url, data, Http Header, etc. to the PHP parser based on the CGI protocol. The PHP parser then parses the php.ini file, initializes the execution environment, processes the request, returns the processed results in the format specified by CGI, and exits the process.The web server then returns the results to the browser.The entire process is shown in the figure above.

FastCGI

Here, the PHP parser is the program that implements the CGI protocol. Each time a request comes, it parses the php.ini file and initializes the execution environment, which results in poor performance of the PHP parser and an improved upgrade of the CGI, FastCGI, appears.FastCGI is a language-independent protocol for communicating programs (such as PHP, Python, Java) and Web servers (Apache 2, Nginx). Programs written in any language can theoretically provide Web services through FastCGI.It is characterized by dynamically allocating processing processes to requests for efficiency, and most FastCGI implementations maintain a process pool.FastCGI starts a master process, parses the configuration file, initializes the execution environment, and then starts multiple worker processes.When a request comes in, the master process passes the request to a worker process and immediately accepts the next request.And when the worker process is not enough, the master can start several worker processes in advance according to the configuration to wait; of course, when there are too many idle worker processes, they will automatically shut down, which improves performance and saves system resources.FastCGI plays the role of managing CGI processes throughout the process.

PHP-FPM

PHP-FPM is a program that implements the FastCGI protocol specifically for PHP. It is actually a PHP FastCGI process manager that manages a process pool and calls the PHP parser to process requests from the Web server.PHP-FPM can smoothly override modifications to php.ini files.

Create a new helloworld.php file and write the following code

<?php
   echo "helloworld,";    
   echo "this is my first php script.";
   echo phpinfo();
?>

After configuring php runtime environments such as WebServer and PHP-FPM, accessing the file in the browser can get the output directly.

PHP-based Web Framework

The PHP Web framework is

Encapsulate common PHP development functionality based on a pattern to implement tools for rapid developer development

Its main tasks include:

  • Code reuse: Defines the placement and loading rules for packages, classes, and functions, and suggests direct integration of Composer and its AutoLoad features.

  • Distribution management of requests: This is routing, the Rest wind framework likes Rewrite, and the simpler framework mainly uses parameters to locate modules and methods.

  • Profile management: loading and dynamically loading configuration data

  • Error and exception management: exception capture, error logging, and error code specifications.

  • Layout and Template Engine: How to plan page layouts, how widget s are reused, how ajax pages are combined, how expiration-session s are redirected, how data and templates are rendered as HTML, whether or not to compress and set expiration headers.

  • Database: how to integrate into the controller; what driver is supported; considers the extensibility of master-slave separation; and whether or not to use ORM

Analysis of ThinkPHP3.2 Framework Processing Flow

TP's design logic is simple and rough, so it solves problems in the face of problems, so its processing process is based on Process-oriented thinking, rather than object-oriented dependency injection, control inversion and other ideas.His automatic loading and error handling are achieved through callbacks to php native functions.TP takes four steps to process each request as shown in the following figure:

Call application intersection index.php

index.php is the entry file for TP. All requests are taken over by this file. It is also simple to import the ThinkPHP entry file.

<?php


// Apply Entry File


 


// Detecting PHP environments


if(version_compare(PHP_VERSION,'5.3.0','<'))  die('require
 PHP > 5.3.0 !');


 


// Turn on debugging mode Suggest development phase turn on deployment phase comment or set to false


define('APP_DEBUG',False);


 


// Define application directory


define('APP_PATH','./Application/');


 


// Introduce ThinkPHP entry file


require
'./ThinkPHP/ThinkPHP.php';

Load Framework Entry File ThinkPHP.php

In ThinkPHP.php, the initial run time and memory overhead are recorded, the system constants are judged and defined, the ThinkThink class is loaded, and the Think::start method is executed for application initialization.

Apply Initialization ThinkThink:start()

Application Initialization Sets Error Handling and Automatic Loading Mechanisms First

static public function start() {
      // Register AUTOLOAD method
      spl_autoload_register('Think\Think::autoload');      
      // Set Errors and Exception Handling
      register_shutdown_function('Think\Think::fatalError');
      set_error_handler('Think\Think::appError');
      set_exception_handler('Think\Think::appException');

Then load the configuration file and the run mode definition file, and finally call the run method of the ThinkApp class to start the application

Run App::run()

Thereafter, TP enters the request processing pipeline. TP defines 14 events in the pipeline. Each event can be bound to a callback function. These events are triggered one after the request arrives in the pipeline. When the event is triggered, the callback function bound to the event is invoked. The life cycle of the entire pipeline begins with app_init and ends with app_end.Specifically, TP names these events as labels (bits), or hooks, and callback functions as behaviors. When an application runs to a label, it is intercepted and related behaviors are uniformly executed.

Laravel Framework Process Analysis

Unified Entry

The Laravel framework uses a unified entry file: /public/index.php

<?php
//Automatic Loading File Settings
require __DIR__.'/../bootstrap/autoload.php';
 
//Initialize the Service Container (check out the documentation on Service Container)
$app = require_once __DIR__.'/../bootstrap/app.php';
 
//Generating an instance of a kernel class from a service container (Illuminate\Contracts\Http\Kernel is actually just an interface, the real instance generated is the App\Http\Kernel class, check the Contracts documentation on how to associate interfaces with classes)
$kernel = $app->make('Illuminate\Contracts\Http\Kernel');
 
//Run the handle method of the Kernel class, the main action being to run the middleware and start URL related Contrller s
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);
 
//The operation after the controller returned the result, which has not been seen yet, should be added later
$response->send();
 
$kernel->terminate($request, $response);

Auto Load Files

Automatic loading of laravel s, which is actually the automatic loading of Composer s
Composer downloads code files from the source of related libraries based on declared dependencies and generates PHP scripts for class autoloading in the Composer directory based on dependencies. When used, you can directly instantiate classes in these third-party class libraries by introducing a'/vendor/autoload.php'file at the beginning of the project.

Service Container - The Real Core of Laravel

Service containers, also known as IoC containers, consist of Dependent Injection (DI) and Control Inversion (IoC), which are the true cores of Laravel.Other functional modules, such as Route, Eloquent ORM, Request and Response, and so on, are actually provided by core-independent class modules, ranging from registration to instantiation and ultimately to use, which are actually the responsibility of Laravel's service containerOf.

Start Kernel Code

The Kernel instance calls the handle method, which means that Laravel's core and common code are ready and the project is officially running

Code List/app/Http/Kernel.php

<?php
namespace
App\Http;


use
Illuminate\Foundation\Http\Kernel
as
HttpKernel;


class
Kernel
extends
HttpKernel
{


    //This is the middleware that needs to be started before routing is invoked. It is usually a core file and should not be modified


    protected
$middleware
=
[


        'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',


        'Illuminate\Cookie\Middleware\EncryptCookies',


        'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',


        'Illuminate\Session\Middleware\StartSession',


        'Illuminate\View\Middleware\ShareErrorsFromSession',


        'App\Http\Middleware\VerifyCsrfToken',


    ];


    //This is the MIDDLWARE element that we can use inside the router.php file or the Controller file and add a lot of customizations


    protected
$routeMiddleware
=
[


        'auth'
=>
'App\Http\Middleware\Authenticate',


        'auth.basic'
=>
'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',


        'guest'
=>
'App\Http\Middleware\RedirectIfAuthenticated',


        'test'
=>
'App\Http\Middleware\testMiddleWare',


    ];


}

As you can see, there are actually no handle methods in this file, only some attribute definitions, so the real handle methods are implemented in the parent class.

Code List.../Illuminate/Foundation/Http/Kernel.php

//This is important, as are some of the project's startup bootstraps. The first important step for Kernel is to start the bootstrap method for these files
protected $bootstrappers = [
        //Detect if environment variable files are working
        'Illuminate\Foundation\Bootstrap\DetectEnvironment',
        //Get the configuration file, that is, read all the configuration files under / config / to the container (app () ->make ('config') to view all the configuration information)
        'Illuminate\Foundation\Bootstrap\LoadConfiguration',
        //How do I access an instance named log bound to a container?(app()->make('log'))
        'Illuminate\Foundation\Bootstrap\ConfigureLogging',
        //Setting exception grab information has not been carefully reviewed, but it probably means that
        'Illuminate\Foundation\Bootstrap\HandleExceptions',
        //The aliases item in /config/app.php is aliased using the PHP library function class_alias, from which we can get an instance using App::make('app')
        'Illuminate\Foundation\Bootstrap\RegisterFacades',
        //Register the providers item in/config/app.php with the container
        'Illuminate\Foundation\Bootstrap\RegisterProviders',
        //Run boot methods from all ServiceProvider s registered in the container
        'Illuminate\Foundation\Bootstrap\BootProviders',
    ];
 
  //True handle method
  public function handle($request)
    {
        try
        {
            //Mainly this line, dispatching the methods that need to be run
            return $this->sendRequestThroughRouter($request);
        }
        catch (Exception $e)
        {
            $this->reportException($e);
            return $this->renderException($request, $e);
        }
    }
 
    protected function sendRequestThroughRouter($request)
    {
        $this->app->instance('request', $request);
        Facade::clearResolvedInstance('request');
        //Run the bootstrap method of the file contained in the $bootstrappers above for the purpose noted above
        $this->bootstrap();
        //This is some preparation before the URL is scheduled, that is, before Route is run
        return (new Pipeline($this->app))    
                    ->send($request)        
                    //Need to run the middleware contained in $this->middleware
                    ->through($this->middleware)
                    //After running the above middleware, dispatchToRouter method is dispatched for Route operation
                    ->then($this->dispatchToRouter());
    }
 
    //Route after the prelude is finished
    protected function dispatchToRouter()
    {
        return function($request)
        {
            $this->app->instance('request', $request);
            //The dispatch method to jump to the Router class
            return $this->router->dispatch($request);
        };
    }

Next you need to Route based on the URL and/app/Http/routes.php file

File List.../Illuminate/Routing/Router.php

public
function
dispatch(Request
$request)


{


$this->currentRequest
=
$request;


//Route has a filter property in version 4.2; versions after 5.0 are replaced by Middleware


$response
=
$this->callFilter('before',
$request);


if
(is_null($response))


{    


//Continue scheduling


$response
=
$this->dispatchToRoute($request);


}


$response
=
$this->prepareResponse($request,
$response);


//Route has a filter property in version 4.2; versions after 5.0 are replaced by Middleware


$this->callFilter('after',
$request,
$response);


return
$response;


}


 


public
function
dispatchToRoute(Request
$request)


{


$route
=
$this->findRoute($request);


$request->setRouteResolver(function()
use
($route)


{


return
$route;


});


$this->events->fire('router.matched',
[$route,
$request]);


$response
=
$this->callRouteBefore($route,
$request);


if
(is_null($response))


{


//
 //Look at this line only or dispatch files


$response
=
$this->runRouteWithinStack(


$route,
$request


);


}


$response
=
$this->prepareResponse($request,
$response);


$this->callRouteAfter($route,
$request,
$response);


return
$response;


}


 


protected
function
runRouteWithinStack(Route
$route,
Request
$request)


{


//
 //Get the Middleware node inside routes.php


$middleware
=
$this->gatherRouteMiddlewares($route);


//This is a bit familiar


return
(new
Pipeline($this->container))


->send($request)


//Execute the above Middleware


->through($middleware)


->then(function($request)
use
($route)


{    


//To Controller class


return
$this->prepareResponse(


$request,


//run Controller


$route->run($request)


);


});


}


 


public
function
run(Request
$request)


{


$this->container
=
$this->container
?:
new
Container;


try


{


if
(
!
is_string($this->action['uses']))


return
$this->runCallable($request);


if
($this->customDispatcherIsBound())


//This line is actually running


return
$this->runWithCustomDispatcher($request);


 


//Actually, I just want to run this line


return
$this->runController($request);


}


catch
(HttpResponseException
$e)


{


return
$e->getResponse();


}


}


 


//Continue scheduling and eventually dispatch to the.../Illuminate/Routing/ControllerDispatcher.php file


protected
function
runWithCustomDispatcher(Request
$request)


{


list($class,
$method)
=
explode('@',
$this->action['uses']);


 


$dispatcher
=
$this->container->make('illuminate.route.dispatcher');


return
$dispatcher->dispatch($this,
$request,
$class,
$method);
}

File List.../Illuminate/Routing/Controller Dispatcher.php

public
function
dispatch(Route
$route,
Request
$request,
$controller,
$method)


    {


        $instance
=
$this->makeController($controller);


        $this->assignAfter($instance,
$route,
$request,
$method);


        $response
=
$this->before($instance,
$route,
$request,
$method);


        if
(is_null($response))


        {


            //Also schedule


            $response
=
$this->callWithinStack(


                $instance,
$route,
$request,
$method


            );


        }


        return
$response;


    }


 


    protected
function
callWithinStack($instance,
$route,
$request,
$method)


    {


        //Again Middleware... Did you forget that Middleware can be added to the controller's constructor in the official document?!Yes, this Middleware was declared in the controller


        $middleware
=
$this->getMiddleware($instance,
$method);


        //It's this again, familiar-eyed


        return
(new
Pipeline($this->container))


                    ->send($request)


                    //Run Middleware again


                    ->through($middleware)


                    ->then(function($request)
use
($instance,
$route,
$method)


                    {    


                        //Run the controller and return the results


                        return
$this->call($instance,
$route,
$method);


                    });


    }

Finally arrived at the controller

From: http://www.eurekao.com/PHP-pr...

Keywords: PHP Laravel Web Server Session

Added by squimmy on Mon, 15 Jul 2019 19:40:35 +0300