Several methods for parsing global variables in PHP

Source: Internet
Author: User
This article provides a detailed analysis of several methods for using global variables in PHP. For more information, see Introduction
Even if you develop a new large PHP program, you must use global data, because some data requires different parts of your code. Some common global data includes program setting, database connection, and user data. There are many ways to make this data a global data. The most common one is to use the "global" keyword Declaration. we will explain it in detail later.
The only drawback of using the "global" keyword to declare global data is that it is actually a very poor programming method, and it often causes a larger problem in the program, because global data links all the original code segments in your code, the consequence is that if you change a part of the code, other parts may encounter errors. Therefore, if your code contains many global variables, your entire program will inevitably be difficult to maintain.

This article will show how to prevent such global variables through different technologies or design patterns. Of course, let's first look at how to use the "global" keyword for global data and how it works.

Use global variables and the "global" keyword
PHP defines some "Superglobals" variables by default. these variables are automatically normalized and can be called anywhere in the program, such as $ _ GET and $ _ REQUEST. They generally come from data or other external data. using these variables will not cause problems, because they are basically not writable.

However, you can use your own global variables. With the keyword "global", you can import global data to a local range of a function. If you do not understand the scope of use of variables, please refer to the relevant instructions in the PHP Manual.
The following is an example of using the "global" keyword:

The code is as follows:


$ My_var = 'Hello World ';
Test_global ();
Function test_global (){
// Now in local scope
// The $ my_var variable doesn't exist
// Produces error: "Undefined variable: my_var"
Echo $ my_var;
// Now let's important the variable
Global $ my_var;
// Works:
Echo $ my_var;
}
?>


As you can see in the preceding example, the "global" keyword is used to import global variables. It seems to work very well and very easy. why do we need to worry about using the "global" keyword to define global data?
The following are three good reasons:

1. code reuse is almost impossible.
If a function depends on global variables, it is almost impossible to use this function in different environments. Another problem is that you cannot extract this function and use it in other code.

2. it is very difficult to debug and solve the problem.
It is more difficult to trace a global variable than to trace a non-global variable. A global variable may be redefined in some non-obvious include files, even if you have a very good program editor (or IDE) to help you, it takes you several hours to discover the problem.

3. it is very difficult to understand the code.
It is hard to figure out where a global variable comes from and what it is used. During development, you may know every global variable, but after about a year, you may forget at least general global variables, at this time, you will regret using so many global variables.
So what should we use if we do not use global variables? Next let's look at some solutions.
Use function parameters
One way to stop using global variables is to simply pass variables as function parameters, as shown below:

The code is as follows:


$ Var = 'Hello World ';
Test ($ var );
Function test ($ var ){
Echo $ var;
}
?>


If you only need to pass a global variable, this is a very good or even an outstanding solution. but if you want to pass many values, what should you do?
For example, if we want to use a database class, a program setting class, and a user class. In our code, these three classes are used in all components, so they must be passed to each component. If we use the function parameter method, we have to do this:

The code is as follows:


$ Db = new DBConnection;
$ Settings = new Settings_XML;
$ User = new User;
Test ($ db, $ settings, $ user );
Function test (& $ db, & $ settings, & $ user ){
// Do something
}
?>


Obviously, this is not worth it. once we have a new object to be added, we have to add one more function parameter for each function. Therefore, we need to use another solution.

Use Singletons)One way to solve the function parameter problem is to use Singletons instead of function parameters. A single piece is a special type of object. they can only be instantiated once and contain a static method to return the interface of the object. The following example demonstrates How to build a simple single piece:

The code is as follows:


// Get instance of DBConnection
$ Db = & DBConnection: getInstance ();
// Set user property on object
$ Db-> user = 'sa ';
// Set second variable (which points to the same instance)
$ Second = & DBConnection: getInstance ();
// Shocould print 'sa'
Echo $ second-> user;
Class DBConnection {
Var $ user;
Function & getInstance (){
Static $ me;
If (is_object ($ me) = true ){
Return $ me;
}
$ Me = new DBConnection;
Return $ me;
}
Function connect (){
// TODO
}
Function query (){
// TODO
}
}
?>


The most important part in the above example is the function getInstance (). This function returns an instance of this class by using a static variable $ me, thus ensuring that there is only one instance of the DBConnection class.
The benefit of using a single piece is that we do not need to explicitly pass an object, but simply use the getInstance () method to get this object, as if it is like the following:

The code is as follows:


Function test (){
$ Db = DBConnection: getInstance ();
// Do something with the object
}
?>


However, the use of a single piece also has a series of shortcomings. First, how do we define multiple objects in a class? This is impossible because we use a single piece (just as its name is a single piece ). Another problem is that a single piece cannot be tested using individual tests, and this is completely impossible unless you introduce all the stacks, which you obviously don't want to see. This is also the main reason why a single piece is not our ideal solution.

Registration mode
The best way to make some objects available to all components in our code is to use a central container object, use it to include all our objects. Generally, such container objects are called registrars. It is flexible and simple. A simple register object is as follows:

The code is as follows:


Class Registry {
Var $ _ objects = array ();
Function set ($ name, & $ object ){
$ This-> _ objects [$ name] = & $ object;
}
Function & get ($ name ){
Return $ this-> _ objects [$ name];
}
}
?>


The first step to use the register object is to use the set () method to register an object:

The code is as follows:


$ Db = new DBConnection;
$ Settings = new Settings_XML;
$ User = new User;
// Register objects
$ Registry = & new Registry;
$ Registry-> set ('DB', $ db );
$ Registry-> set ('Settings', $ settings );
$ Registry-> set ('user', $ user );
?>


Now our Register object contains all our objects. we mean we need to pass this register object to a function (instead of passing three objects separately ). See the following example:

The code is as follows:


Function test (& $ registry ){
$ Db = & $ registry-> get ('DB ');
$ Settings = & $ registry-> get ('Settings ');
$ User = & $ registry-> get ('user ');
// Do something with the objects
}
?>


Compared with other methods, a major improvement of the register is that when we need to add an object in our code, we no longer need to change everything: all the code that uses the global object in the program), we only need to register a new object in the register, and then it (Translator's note: newly registered object) it can be called in all components immediately.

To make it easier to use the register, we change its call to the single-piece mode (note: Do not use the function transfer mentioned above ). Because only one register is needed in our program, the single-piece mode is very suitable for this task. Add a new method to the registrar class as follows:

The code is as follows:


Function & getInstance (){
Static $ me;
If (is_object ($ me) = true ){
Return $ me;
}
$ Me = new Registry;
Return $ me;
}
?>


In this way, it can be used as a single piece, for example:

The code is as follows:


$ Db = new DBConnection;
$ Settings = new Settings_XML;
$ User = new User;
// Register objects
$ Registry = & Registry: getInstance ();
$ Registry-> set ('DB', $ db );
$ Registry-> set ('Settings', $ settings );
$ Registry-> set ('user', $ user );
Function test (){
$ Registry = & Registry: getInstance ();
$ Db = & $ registry-> get ('DB ');
$ Settings = & $ registry-> get ('Settings ');
$ User = & $ registry-> get ('user ');
// Do something with the objects
}
?>


As you can see, we do not need to pass all private things to a function or use the "global" keyword. Therefore, the Register mode is an ideal solution for this problem, and it is very flexible.

Request wrappers
Although our Register has completely removed the "global" keyword, there is still a type of global variable in our code: Super global variable, such as variable $ _ POST, $ _ GET. Although these variables are very standard and won't cause any problems in your use, in some cases, you may also need to use the register to encapsulate them.
A simple solution is to write a class to provide an interface for getting these variables. This is often referred to as the "request Packer". The following is a simple example:

The code is as follows:


Class Request {
Var $ _ request = array ();
Function Request (){
// Get request variables
$ This-> _ request =$ _ REQUEST;
}
Function get ($ name ){
Return $ this-> _ request [$ name];
}
}
?>


The above example is a simple demonstration. of course, you can do many other things (such as automatically filtering data and providing default values) in request wrapper ).
The following code demonstrates how to call a request interceptor:

The code is as follows:


$ Request = new Request;
// Register object
$ Registry = & Registry: getInstance ();
$ Registry-> set ('request', & $ request );
Test ();
Function test (){
$ Registry = & Registry: getInstance ();
$ Request = & $ registry-> get ('request ');
// Print the 'name' querystring, normally it 'd be $ _ GET ['name']
Echo htmlentities ($ request-> get ('name '));
}
?>


As you can see, now we no longer rely on any global variables, and we completely keep these functions away from global variables.

Conclusion
In this article, we demonstrate how to fundamentally remove the global variables in the code, and replace them with appropriate functions and variables. The registration mode is one of my favorite design patterns, because it is very flexible and can prevent your code from getting messy.
In addition, we recommend that you use function parameters instead of single-piece mode to pass the register object. Although it is easier to use a single piece, it may cause some problems in the future, and it is easier to use function parameters for transmission.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.