The flight framework (Official Website) is a micro PHP framework that is simple, fast, and scalable. With flight, you can quickly and easily create your restful web applications.
Although it is a micro-framework, and the amount of code is indeed small, but when I read the flight code, I feel that it is a unique and exquisite place to design and design, if you think there is a learning value, you have to sort it out and share it.
If you are not familiar with the framework, you can go to the official website to view the documentation. If you need a Chinese document, click here.
If you already know something about flight, let's take a look at how flight works.
<? Phpclass flight {/*** framework engine. * @ var object */Private Static $ engine; // don't allow Object Instantiation private function _ construct () {} private function _ destruct () {} private function _ clone () {}/*** has been seen before. All functions in the framework call * _ callstatic () in the form of static functions in the flight class () this magic method can handle all static functions * @ Param string $ name method name * @ Param array $ Params method parameters * @ return mixed callback results */ Public static function _ callstatic ($ name, $ Params) {static $ initialized = false; If (! $ Initialized) {// here defines the framework's automatic loading mechanism, which is actually done according to the PSR-0 standard require_once _ DIR __. '/autoload. PHP '; // The engine class is where the framework engine is located. SELF: $ engine = new \ flight \ engine (); $ initialized = true;} // here, flight encapsulates a layer of engine. The call to flight static functions is essentially a call to the corresponding functions of the engine class. Return \ flight \ core \ DISPATCHER: invokemethod (Array (SELF: $ engine, $ name), $ Params) ;}// let's take a look at DISPATCHER: invokemethod function namespace flight \ core; class dispatcher {/*** call a Method * @ Param mixed $ func Class Method * @ Param array $ Params class method parameters * @ return mixed function results */public static function invokemethod ($ func, array & $ Params = array ()) {List ($ class, $ method) = $ func; $ instance = is_object ($ class); Switch (count ($ Params) {Case 0: Return ($ instance )? $ Class-> $ method (): $ class: $ method (); Case 1: Return ($ instance )? $ Class-> $ method ($ Params [0]): $ class ::$ method ($ Params [0]); Case 2: Return ($ instance )? $ Class-> $ method ($ Params [0], $ Params [1]): $ class: $ method ($ Params [0], $ Params [1]); case 3: Return ($ instance )? $ Class-> $ method ($ Params [0], $ Params [1], $ Params [2]): $ class ::$ method ($ Params [0], $ Params [1], $ Params [2]); Case 4: Return ($ instance )? $ Class-> $ method ($ Params [0], $ Params [1], $ Params [2], $ Params [3]): $ class :: $ method ($ Params [0], $ Params [1], $ Params [2], $ Params [3]); Case 5: Return ($ instance )? $ Class-> $ method ($ Params [0], $ Params [1], $ Params [2], $ Params [3], $ Params [4]): $ class: $ method ($ Params [0], $ Params [1], $ Params [2], $ Params [3], $ Params [4]); default: return call_user_func_array ($ func, $ Params );}}}
As mentioned in the above comments, automatic loading and PSR-0, I have previously written an article about this part of content. The flight framework is automatically loaded Based on namespace and psr-0 standards:
// Only list the main code for automatic loading: namespace flight \ core; Class Loader {/*** starts/stops autoloader. ** @ Param bool $ enabled enable/disable autoloading * @ Param mixed $ dirs autoload directories */public static function autoload ($ enabled = true, $ dirs = array ()) {if ($ enabled) {spl_autoload_register (Array (_ class __, 'loadclass');} else {spl_autoload_unregister (Array (_ class __, 'loadclass');} If (! Empty ($ dirs) {self: adddirectory ($ dirs) ;}}/*** autoloads classes. ** @ Param string $ class name */public static function loadclass ($ class) {$ class_file = str_replace (Array ('\\','_'), '/', $ class ). '. php'; foreach (SELF: $ dirs as $ DIR) {$ file = $ dir. '/'. $ class_file; If (file_exists ($ file) {require $ file; return ;}}}}
Before proceeding, let's sort out the main classes and functions in flight. The following are the built-in classes of the flight framework:
- Engine class: contains the core functions of this framework. It is responsible for loading HTTP requests, running registered services, and generating the final HTTP response.
- Loader class: It is responsible for loading objects in the framework. Use custom initialization parameters to generate new class instances and maintain a list of reusable class instances. It also handles the automatic loading of the class just mentioned.
- Dispatcher class: It is responsible for distributing and processing events within the framework. An event is a simple alias for a class method or function ). It also allows you to mount other functions on Event hook points to change the input or output of functions.
- Router class: It is responsible for sending an HTTP request to a specified function for processing. It matches the requested URL with a series of user-defined URL paradigms.
- Route class: It is responsible for the specific implementation of routing. The router is equivalent to packaging the route.
- Request class: it represents an HTTP request. All data from $ _ Get, $ _ post, $ _ cookie, and $ _ files must be obtained and accessed through the request class. The default request attributes include URL, base, method, and user_agent.
- Response class: corresponds to the request, which represents an HTTP response. This object includes the return header, HTTP status code, and response body.
- View class: View class is responsible for displaying the output. It provides functions for managing View data during rendering and inserting data into view templates.
- Collection class: it allows you to access data both in array mode and in object mode.
Flight framework functions are divided into two parts, one is the core function:
Flight::map($name, $callback) // Creates a custom framework method.Flight::register($name, $class, [$params], [$callback]) // Registers a class to a framework method.Flight::before($name, $callback) // Adds a filter before a framework method.Flight::after($name, $callback) // Adds a filter after a framework method.Flight::path($path) // Adds a path for autoloading classes.Flight::get($key) // Gets a variable.Flight::set($key, $value) // Sets a variable.Flight::has($key) // Checks if a variable is set.Flight::clear([$key]) // Clears a variable.
Another part is extended functions:
Flight::start() // Starts the framework.Flight::stop() // Stops the framework and sends a response.Flight::halt([$code], [$message]) // Stop the framework with an optional status code and message.Flight::route($pattern, $callback) // Maps a URL pattern to a callback.Flight::redirect($url, [$code]) // Redirects to another URL.Flight::render($file, [$data], [$key]) // Renders a template file.Flight::error($exception) // Sends an HTTP 500 response.Flight::notFound() // Sends an HTTP 404 response.Flight::etag($id, [$type]) // Performs ETag HTTP caching.Flight::lastModified($time) // Performs last modified HTTP caching.Flight::json($data, [$code], [$encode]) // Sends a JSON response.Flight::jsonp($data, [$param], [$code], [$encode]) // Sends a JSONP response.
The flight framework is used to call flight static functions (flight: func (). As mentioned above, the essence is to call functions in engine objects ($ engineobj-> func ()).
There are two types of engine functions. One is the core function, which is called directly (relative to dynamic call), and the other extended function is called dynamically.
In addition, you can load classes and resources in flight to obtain an instance of a class and directly call flight: classname (), which is equivalent to $ engineobj-> classname (). This is also in the form of dynamic calls. That is to say, except for the core functions of the engine class, other functions (classes) are dynamically called. In this way, the Framework provides a unified entrance for this purpose.
Namespace flight; Class engine {//.... public Function _ construct () {$ this-> vars = array (); // As mentioned above, in flight, dispatcher is responsible for processing functions, loader is responsible for loading objects $ this-> loader = new loader (); $ this-> dispatcher = new DISPATCHER (); $ this-> Init ();} /*** _ call is a magic method. When a nonexistent function is called, will call this function * the dynamic call just mentioned is through this function * @ Param string $ name method name * @ Param array $ Params method parameters * @ return mixed callback results * /P Ublic function _ call ($ name, $ Params) {// determine whether the function is a class or can be called directly $ callback = $ this-> Dispatcher-> get ($ name); // if it is a function, if (is_callable ($ callback) {return $ this-> Dispatcher-> Run ($ name, $ Params);} // whether it is a shared instance $ shared = (! Empty ($ Params ))? (Bool) $ Params [0]: true; // load the object of this class through loader return $ this-> loader-> load ($ name, $ shared );} /*** framework initialization */Public Function Init () {static $ initialized = false; $ self = $ this; if ($ initialized) {$ this-> vars = array (); $ this-> loader-> Reset (); $ this-> Dispatcher-> Reset ();} // flight, the class registers the default component $ this-> loader-> Register ('request', '\ flight \ net \ request') through the Register function of loader '); $ this-> loader-> Register ('response', '\ flight \ net \ response'); $ this-> loader-> Register ('router ', '\ flight \ net \ router'); $ this-> loader-> Register ('view', '\ flight \ template \ view', array (), function ($ view) use ($ self) {$ view-> Path = $ self-> get ('flight. views. path ');}); // method of registering the framework $ methods = array ('start', 'stop', 'route', 'halt ', 'error ', 'notfound', 'render', 'redirect', 'etag', 'lastmodified', 'json', 'jsonp'); // flight, method binds the corresponding callback function to an event through the set function of dispatcher. // for dynamic calling, extended enginge functions are all foreach ($ methods as $ name) defined by the _ method name {$ this-> Dispatcher-> set ($ name, array ($ this, '_'. $ name);} // default configuration $ this-> set ('flight. base_url ', null); $ this-> set ('flight. handle_errors ', true); $ this-> set ('flight. log_errors ', false); $ this-> set ('flight. views. path ','. /views '); $ initialized = true;}/*** registers a class to the framework method, we use this function to register ** @ Param string $ name method name * @ Param string $ class name * @ Param array $ Params class initialization parameters *@ param callback $ callback function to call after Object Instantiation * @ throws \ exception if trying to map over a Framework Method */Public Function register ($ name, $ class, array $ Params = array (), $ callback = NULL) {If (method_exists ($ this, $ name )) {Throw new \ exception ('cannot override an existing framework method. ');} // register through the loader's register function $ this-> loader-> Register ($ name, $ class, $ Params, $ callback );} /*** map a callback function to the framework method, we use this function to map the ** @ Param string $ name method name * @ Param callback $ callback function * @ throws \ exception if trying to map over a framework. method */Public Function Map ($ name, $ callback) {If (method_exists ($ this, $ name) {Throw new \ exception ('cannot override an existing framework method. ');} // bind the corresponding callback function to an event through the set function of dispatcher $ this-> Dispatcher-> set ($ name, $ callback );} //...}
The two core functions in flight, map is a ing user-defined function, and finally is implemented through the set function of dispathcer. Register is the registration user-defined class, finally, it is implemented through the Register function of loader. The Core Components and extended functions of the framework help us complete these two processes during the initialization process. Flight then provides a unified portal for dynamic calling of all non-core functions and classes. This is the core Loading Mechanism of flight.
Maybe you still have questions, why does Flight need to access these functions or objects in the form of dynamic calls? Especially for engine extension functions, why not call them directly? Because flight can filter or override them. Filtering and rewriting are important functions of the flight framework for extension. After the framework implements a unified resource operation method, it can be easily rewritten or filtered. It should be noted that core functions such as map and register cannot be filtered or overwritten. I believe you know why.
The rewrite function of the framework still uses the map and register functions. This function is easily completed due to the design of the framework. In both dispatcher and loader, A ing table is dynamically maintained. In dispatcher, the ing from the callback to the event is performed, and in loader, The ing from the class to the instance and constructor is performed. In this way, when registering a user-defined function or class, the same name will overwrite the previous one, and only the latest one will be returned during use. The following is some code of the loader class:
Namespace flight \ core; Class Loader {//.... /*** register a class ** @ Param string $ Name Registry name * @ Param string | callable $ class name or function to instantiate class * @ Param array $ Params class initialization parameters * @ Param callback $ callback function to call after Object Instantiation */Public Function register ($ name, $ class, array $ Params = array (), $ callback = NULL) {unset ($ this-> INS Tances [$ name]); $ this-> classes [$ name] = array ($ class, $ Params, $ callback );} /*** load a registered class ** @ Param string $ name method name * @ Param bool $ shared instance * @ return object class instance */Public Function load ($ name, $ shared = true) {$ OBJ = NULL; // $ this-> classes is the registered class // $ this-> instances is the loaded instance if (isset ($ this-> classes [$ name]) {list ($ class, $ Params, $ callback) = $ this-> classes [$ Nam E]; $ exists = isset ($ this-> instances [$ name]); // is it a shared instance if ($ shared) {$ OBJ = ($ exists )? $ This-> getinstance ($ name): $ this-> newinstance ($ class, $ Params); If (! $ Exists) {$ this-> instances [$ name] = $ OBJ ;}} else {$ OBJ = $ this-> newinstance ($ class, $ Params );} if ($ callback &&(! $ Shared |! $ Exists) {$ ref = array (& $ OBJ); call_user_func_array ($ callback, $ ref) ;}return $ OBJ ;} /*** get a single instance of a class ** @ Param string $ name Instance name * @ return object class instance */Public Function getinstance ($ name) {return isset ($ this-> instances [$ name])? $ This-> instances [$ name]: NULL ;} /*** get a new instance of a class ** @ Param string | callable $ class name or callback function to instantiate class * @ Param array $ Params class initialization parameters * @ return object class instance */Public Function newinstance ($ class, array $ Params = array () {If (is_callable ($ class) {return call_user_func_array ($ class, $ Params);} switch (count ($ Params )) {Case 0: return new $ class (); Case 1: return new $ class ($ Params [0]); Case 2: return new $ class ($ Params [0], $ Params [1]); Case 3: return new $ class ($ Params [0], $ Params [1], $ Params [2]); Case 4: return new $ class ($ Params [0], $ Params [1], $ Params [2], $ Params [3]); Case 5: return new $ class ($ Params [0], $ Params [1], $ Params [2], $ Params [3], $ Params [4]); default: $ refclass = new \ reflectionclass ($ class); return $ refclass-> newinstanceargs ($ Params );}}//....}
Functions related to the filter function are before and after, which are operated before or after the filter function is processed. It is implemented in the dispatcher class.
Namespace flight; Class engine {/*** adds a pre-filter to a method. ** @ Param string $ name method name * @ Param callback $ callback function */public function before ($ name, $ callback) {$ this-> Dispatcher-> hook ($ name, 'before', $ callback);}/*** adds a post-filter to a method. ** @ Param string $ name method name * @ Param callback $ callback function */Public Function after ($ Nam E, $ callback) {$ this-> Dispatcher-> hook ($ name, 'after', $ callback) ;}} namespace flight \ core; class dispatcher {/*** registers the callback to an event ** @ Param string $ name event name * @ Param callback $ callback function */public function set ($ name, $ callback) {$ this-> events [$ name] = $ callback ;} /*** get the callback associated with the event ** @ Param string $ name event name * @ return callback $ callback function */Public Fu Nction get ($ name) {return isset ($ this-> events [$ name])? $ This-> events [$ name]: NULL ;} /*** mount a callback function on the event ** @ Param string $ name event name * @ Param string $ type filter type * @ Param callback $ callback function */Public Function hook ($ name, $ type, $ callback) {$ this-> filters [$ name] [$ type] [] = $ callback ;} /*** dispatch events ** @ Param string $ name event name * @ Param array $ Params callback parameters * @ return string output of callback */Public Function run ($ name, array $ Params = array () {$ output = ''; // run the pre-filter if (! Empty ($ this-> filters [$ name] ['before']) {$ this-> filter ($ this-> filters [$ name] ['before'], $ Params, $ output);} // run the requested method $ output = $ this-> execute ($ this-> get ($ name), $ Params ); // run the post filter if (! Empty ($ this-> filters [$ name] ['after']) {$ this-> filter ($ this-> filters [$ name] ['after'], $ Params, $ output) ;}return $ output ;}}
Next, what is the processing process for running this framework?
Namespace flight; Class engine {/*** start this framework */public function _ start () {$ dispatched = false; $ self = $ this; $ request = $ this-> request (); $ response = $ this-> response (); $ router = $ this-> router (); // clears the existing output if (ob_get_length ()> 0) {$ response-> write (ob_get_clean ();} // starts the output buffer ob_start (); // enable error handling $ this-> handleerrors ($ this-> get ('flight. handle_errors '); // disable the cache for Ajax requests if ($ request-> Ajax ){ $ Response-> cache (false);} // allows the post filter to run $ this-> after ('start', function () use ($ self) {// After the start is complete, the STOP () function $ self-> stop () ;}) is called ();}); // route the request while ($ route = $ router-> route ($ request) {$ Params = array_values ($ route-> Params ); // whether to continue the route chain $ continue = $ this-> Dispatcher-> execute ($ route-> callback, $ Params); $ dispatched = true; If (! $ Continue) break; $ router-> next () ;}// the route does not match if (! $ Dispatched) {$ this-> notfound ();}} /*** stop the framework and output the current response content ** @ Param int $ code HTTP Status Code */public function _ stop ($ code = 200) {$ this-> response ()-> Status ($ Code)-> write (ob_get_clean ()-> send ();}}
So far, we should have a certain understanding of the flight core design, functions, and processing processes. As for other routes, the request has been responded to and other content, so let the readers learn it by themselves.
-EOF-
Understand the core of the flight framework