Author: Vallo Reima
Viewers: 213
Last month viewers: 8
Categories: PHP Tutorials
Read this article to learn about the Gateway pattern, an additional way to access common application data besides better known ways that use global and static variables.
Contents
Introduction
Global Data
The Static Approach
The Gateway Pattern Approach
Conclusion
Introduction
In the context of this article, common data are variables or functions that are accessed throughout many parts of the code of an application during each execution.
In larger projects, having an easy way to access common data becomes more important because it is accessed many times from the many parts of the project code.
There are different design patterns that can help on this purpose like Dependency Injection, Singleton, etc.. The approaches described here represent additional options that you have. This article does not concern the data saved between requests that is usually stored in sessions.
Global Data
There are several ways to access frequently used functions and variables. The most obvious way is to place them in the global scope, for instance defining them in the beginning of the script. When calling a function, the necessary data can be passed using parameters. Then we get the result back with return statement or have the function modify the arguments passed by reference.
This works well in simple programs but in more complex systems, passing frequently used variables continuously throughout many functions becomes hard to maintain. For example, many functions may need a database connection to read or update the information, a list of text strings to display in messages, etc..
The global keyword and the $GLOBALS super-global variable can be used to avoid frequent parameter passing. Common variables are accessed directly inside the functions.
Placing common data into the global scope gets in the way of the OOP paradigm. There are multiple places in the program which may change the global data and the function names may conflict with each other. The program logic becomes difficult to follow, debugging and testing becomes more complicated.
The Static Approach
A better way to organize common data is to use static variables and functions. Declaring class variables or functions as static makes them accessible without needing to create an object of the class. Common data is encapsulated in public functions that can provide a way access to internal private variables and functions. Here is example:
class Site { /* global variables & functions - static approach */ public static $title; public static $lang ; /* settings */ private static $txts = array( /* texts */ 'en_tit' => 'A static approach to manage global data', 'en_hi' => "Thank's for attention!"); public static function Config($lng) /* set configuration */ { self::$lang = $lng; self::Init(); } private static function Init() /* init globals */ { self::$title = self::Msg('tit'); } public static function Msg($txt) /* form a message */ { $t = self::$lang . '_' . $txt; return self::$txts[$t]; } } Site::Config('en'); /* startup */ Bye(); /* finish */ function Bye() /* exit the program */ { $m = Site::$title . '. ' . Site::Msg('hi'); die($m); }
The Config() function is accessed from global scope. The $title variable and the Msg() function are accessed from within the Bye() function. The private property $txts is used internally. The Config() calls the Init() private method.
Common data is encapsulated and prefixed by the class name throughout whole program. That avoids name collisions and does not compromise the OOP principles. But it is still difficult to follow the calls to common functions and changes of common variables from multiple points in larger programs.
The Gateway Pattern Approach
The idea of the gateway pattern is to gather all the common data to access in single point. Through this point, the gateway, all the common access can be controlled and observed.
PHP 5.3 introduced the namespaces for gathering related components. Namespaces are handy for separating the program code from third-party classes, functions and constants, but own common data should be accessed in another way. This is where another useful feature introduced in PHP 5.3, the __callStatic() magic function, comes to play.
The common gateway is implemented by two classes: the gateway itself, containing some static variables and functions, and the common data class, holding the functions and variables as methods and properties.
Since the gateway will be accessed many times in the application, its class name should be short. The '¤' symbol is used here as an example to access the gateway in way that is noticeable in your code:
/** * gateway to common methods & properties * * @package System * @author Vallo Reima * @copyright (C)2012 */ class ¤ { public static $_; /* commons instance */ public static function Init($class) { self::$_ = new $class(); /* instantiate the commons class */ } public static function __callStatic($func, $args) { /* access common method */ return call_user_func_array(array(self::$_, $func), $args); } } ¤::Init('Site');
The gateway class must be included in the beginning of the application. The common data class must be instantiated via the Init() method. For example, the ¤::Init('Site') statement above instantiates the Site class of common data and assigns its object value to the $_ property (this name is also picked to be as short as possible for frequent accesses). The Site class must be included or loaded via autoload before the Init() call.
The common data class contains public variables and functions (not static) like global functions and variables, and private variables and functions for internal use. Common variables can be organized in several ways. A good choice is to hold them in the stdClass() object and access via __get() and __set() magic methods.
An example below demonstrates the gateway approach with Site class rewritten from previous example:
class Site { /* common variables and functions - gateway approach */ private $data; /* common variables structure */ private $txts = array(/* texts */ 'en_tit' => 'A gateway approach to manage common data', 'en_hi' => "Thank's for attention!"); public function __construct() /* create a variables structure */ { $this->data = new stdClass(); } public function __get($prp) /* get common variable value */ { return $this->data->$prp; } public function __set($prp, $val) /* get common variable value */ { $this->data->$prp = $val; } public function Config($lng) /* set configuration */ { $this->data->lang = $lng; $this->Init(); } private function Init() /* init commons */ { $this->title = $this->Msg('tit'); } public function Msg($txt) /* form a message */ { $t = $this->data->lang . '_' . $txt; return $this->txts[$t]; } } ¤::Init('Site'); /* instantiate commons */ ¤::Config('en'); /* startup */ Bye(); /* finish */ function Bye() /* exit the program */ { $m = ¤::$_->title . '. ' . ¤::Msg('hi'); die($m); }
The common class functions Config() and Msg() are called through the gateway class using overloading of __callStatic method (see the gateway example).
The common variable $title is accessed via the gateway property $_ using the property overloading within the common data class. Unfortunately, property overloading for a static context (like __getStatic and __setStatic) is not supported yet by PHP. Therefore a prefix ¤::$_-> is needed for common variables. But these functions added by the gateway class can be complemented to allow a shorter notation (like ¤::$title instead of ¤::$_->title).
Conclusion
There is no universal solution for all problems. This applies to common data access too. The static approach could be used for smaller projects and gateway approach for larger ones. It is important to plan for the right type of usage of your application.
Constants could be used instead of the variables. Constants are initialized once and not changed during the program execution. The variable values not used very frequently could be passed as parameters between the functions.
An argument against wrapping the common data into the classes is a slower performance. But the speed difference is most likely negligible in most applications, as I/O operations like file, network and database accesses are usually the bottleneck. An effective control over data flow weights up a loss in speed.
However, functions and variables that are used so often that can affect performance, can be placed in the global scope and then we use of the global keyword inside functions.
The gateway class approach can be complemented with other approaches to have more control over common data.
If you liked this article or have questions, please post a comment to this article.
You need to be a registered user or login to post a comment
1,616,820 PHP developers registered to the PHP Classes site.
Be One of Us!
Login Immediately with your account on:
Comments:
1. Excellent tutorial - Yoni Lamri (2015-05-12 09:54)
Excellent tutorial... - 1 reply
Read the whole comment and replies