The PHP design mode introduces the unique mode. In almost all object-oriented programs, one or two resources are created and used continuously in application sharing. For example, in almost all object-oriented programs of an e-commerce program, one or two of these resources are created and shared in the application. For example, such a resource is used in the database connection of an e-commerce program: the connection is initialized when the application starts, and the program can be executed effectively. when the program ends, the connection is eventually disconnected and destroyed. If you write code, you do not need to create a database connection every moment, which is very inefficient. The established connections should be easily and repeatedly used by your code. The question is, based on the above requirements, how will you connect to this database? (Or connect to other unique resources that are recycled, such as an open file or a queue .)
Problem
How do you ensure that an instance of a special class is unique (it is the only instance of this class) and it is easy to access?
Solution
Of course, global variables are an obvious solution. But it is like Pandora's Box (correct judgment comes from experience, and wrong judgment produces experience. This proverb means this .), You can modify global variables for any code, which will inevitably lead to more debugging exceptions. In other words, the state of the global variable will always have some problems, (there is a good description about the use of the global variable here, http://c2.com/cgi/wiki? GlobalVariablesAreBad ).
When you need a unique instance of a special class, use the single-piece mode. Classes based on the single-piece mode can instantiate and initialize an instance of this class, and provide absolutely identical connections every moment. Generally, the static method named getInstance () is used for implementation.
The key issue is how to obtain a precise and unified instance every moment. See the following example:
// PHP4
Function TestGetInstance (){
$ This-> assertIsA (
$ Obj1 = & DbConn: getInstance (),
'Dbconn ',
'The returned object is an instance of dbconn ');
$ This-> assertReference (
$ Obj1,
$ Obj2 = & DbConn: getInstance (),
'Two callto getInstance () return the same object ');
}
Note: assertReference
The assertReference () method ensures that two passed parameters reference the same PHP variable.
In PHP4, two tested parameters are asserted to be the same object. The assertReference () method may not be recommended after it is transplanted to PHP5.
This test method has two assertions: the first judge that the value returned by the static method DbConn: getInstance () is the instance of the DbConn object, and the second is used to judge the second call of getInstance () the value returned by the method references the same object instance, which means they use the same object.
In addition to asserted the expected execution results of the code, Test also indicates the correct usage of getInstance () (PHP4): $ local_conn_var = & DbConn: getInstance (). The return value of the reference (= &) static method is assigned to this local variable.
Write another test code: using "new" to instantiate a single-piece class will cause some types of errors. The test code is as follows:
Function TestBadInstantiate (){
$ Obj = & new DbConn;
$ This-> assertErrorPattern (
'/(Bad | nasty | edevil | do not | don \' t | warn ).*'.
'(Instance | create | new | direct)/I ');
}
This code directly creates a DbConn instance, which will cause PHP errors. To make the code more stable, we use the PCRE regular expression to match the error message. (The exact wording of the error message is not important .)
[Next]
Sample code
The single-piece mode is an interesting mode. Let's use PHP4 and PHP5 to explore its implementation process, starting from PHP4.
Global Mode
Theoretically, a global variable can generate a perfect single piece, but the global variable may be modified: During code running, it cannot be guaranteed that the global variable points to an object. Therefore, you can reduce the problem of "too random access" by not allowing global variables to be directly referenced globally. For example, this code uses a very long and unique name to "hide" references to global variables.
Class DbConn {
Function DbConn ($ fromGetInstance = false ){
If (M_E! = $ FromGetInstance ){
Trigger_error ('The DbConn class is a Singleton ,'
. 'Please do not instantiate directly .');
}
}
Function & getInstance (){
$ Key = '_ some_unique_key_for_the_DbConn_instance __';
If (! (Array_key_exists ($ key, $ GLOBALS) & is_object ($ GLOBALS [$ key])
& 'Dbconn' = get_class ($ GLOBALS [$ key]) {
$ GLOBALS [$ key] = & new DbConn (M_E );
}
Return $ GLOBALS [$ key];
}
}
In the DbConn Conn constructor, you may be confused about the default parameter $ fromGetInstance. When an object is directly instantiated, it provides (very weak) protection: unless the default value is e (M_E = 2.718281828459 in the PHP mathematical constant), this code will report an error.
A uml class diagram. the solution is as follows:
If you do not select this "mysterious parameter"-type protection, creating a global tag is another option. you can use it to verify that you created an object through the getInstance () method. The protection method is changed from "you know its name" to "it exists in the environment ".
The following example explains why the constructor protection code has a global identifier:
Class DbConn {
Function DbConn (){
$ Token = '_ some_DbConn_instance_create_semaphore __';
If (! Array_key_exists ($ token, $ GLOBALS )){
Trigger_error ('The DbConn class is a Singleton ,'
. 'Please do not instantiate directly .');
}
}
Function & getInstance (){
Static $ instance = array ();
If (! $ Instance ){
$ Token = '_ some_DbConn_instance_create_semaphore __';
$ GLOBALS [$ token] = true;
$ Instance [0] = & new DbConn;
Unset ($ GLOBALS [$ token]);
}
Prompt
PHP4 allows you to change the value of $ this in the constructor. In the past, we used to set $ this = null. When an error occurred while creating the constructor, make sure that the invalid object cannot be used by the code. Something useful in PHP4 is incompatible with PHP5 and will be verified in your code in the future. this technology is no longer recommended.
Another important part of this code is reference Operations & usage. There are two ways to use &. The first type is used before the function name to indicate that a reference will be returned during function definition. The second is to assign a new DbConn object to the $ GLOBALS array. (Mentioned in the preface and value object chapter: in PHP4, you will always use the & operator to create, pass, and return objects in reference mode ,)
The condition check of the getInstance () method is often written to run without warning, and is not prompted even at the E_ALL error level. It checks whether there is a DbConn object in the appropriate position in the $ GLOBAL Array. if not, create this object there. This method returns such a result. this object can be repeatedly created or this object has been created by this method before. When the method ends, you can confirm that you already have a valid instance of this class and that it has been effectively initialized.
[Next]
Static Mode
Global variables are even hidden in global variables of getInstance. Because global variables are valid anywhere in the script, you may still destroy this global variable without notice,
Using static variables to store Singleton in the getInstance () method is a clean method. The first code snippet is as follows:
Class DbConn {
//...
Function & getInstance (){
Static $ instance = false;
If (! $ Instance) $ instance = & new DbConn (M_E );
Return $ instance;
}
}
The Zend 1 engine cannot store references to static variables in PHP4 (see the http://www.php.net/manual/en/language.variables.scope.php#AEN3609 ). Use a workspace to store static arrays and place references to this single-piece instance in a known array. The getInstance () method is as follows:
Class DbConn {
Function DbConn ($ fromGetInstance = false ){
If (M_E! = $ FromGetInstance ){
Trigger_error ('The DbConn class is a Singleton ,'
. 'Please do not instantiate directly .');
}
}
Function & getInstance (){
Static $ instance = array ();
If (! $ Instance) $ instance0 = & new DbConn (M_E );
Return $ instance0;
}
}
This code selects the first element of the static array $ instancede to maintain reference of a single-piece DbConns instance.
Although this code is a bit dependent on the Boolean PHP method, it is more rigorous than the global version: in condition detection, using an empty array will result in false. Just like in the previous version of the DbConn class, operators need to be referenced in the definition and assignment of functions.
Single-piece mode in PHP5
PHP5 makes it easier to implement the single-piece mode. PHP5 has enhanced its access control over internal variables and functions of the class. The DbConn: _ construct () constructor is set to private, so this class cannot be directly instantiated. In a UML diagram, the DbConn single-piece mode of PHP5 is as follows:
Use static methods and static variables together to keep this instance and set the constructor to private to prevent instance creation by directly instantiating the class. the code is as follows:
Class DbConn {
/**
* Static property to hold singleton instance
*/
Static $ instance = false;
/**
* Constructor
* Private so only getInstance () method can instantiate
* @ Return void
*/
Private function _ construct (){}
/**
* Factory method to return the singleton instance
* @ Return DbConn
*/
Public function getInstance (){
If (! DbConn: $ instance ){
DbConn: $ instance = new DbConn;
}
Return DbConn: $ instance;
}
}
Note: For more exciting articles, please follow the help HouseProgramming TutorialTopic.
Bytes. For example, such a resource in an e-commerce program...