In the article "Do you know PHP design patterns", we briefly introduced the factory pattern. Today we will take a detailed look at the application scenarios of the factory pattern in PHP development.
To learn more about PHP design patterns, please visit: Talk about PHP design patterns
Originally in the book Design Patterns, many design patterns encourage the use of loose coupling. To understand this concept, it's best to talk about the arduous journey that many developers go through working on large systems. When you change one piece of code, problems can occur, and cascading breaks can occur in other parts of the system—parts you once thought were completely unrelated.
The problem is tight coupling. Functions and classes in one part of the system are heavily dependent on the behavior and structure of functions and classes in other parts of the system. You want a set of patterns that allow these classes to communicate with each other, but you don't want to tie them tightly together to avoid interlocking.
In large systems, a lot of code depends on a few key classes. Difficulties may arise when these classes need to be changed. For example, suppose you have a User class that reads from a file. You want to change it to a different class that reads from the database, however, all your code references the original class that reads from the file. At this time, it will be very convenient to use factory mode.
Factory pattern is a class that has certain methods that create objects for you. You can use a factory class to create objects without using new directly. This way, if you want to change the type of object created, you only need to change the factory. All code using this factory is automatically changed.
Example 1: Display a column of the factory class. The server side of the equation consists of two parts: a database and a set of PHP pages that allow you to add feedback, request a list of feedback, and get articles related to a specific feedback.
<ol class="dp-c"><li class="alt"><span><span><?php </span></span><li> <span class="keyword">interface</span><span> IUser </span> </li> <li class="alt"><span>{ </span></li> <li> <span> </span><span class="keyword">function</span><span> getName(); </span> </li> <li class="alt"><span>} </span></li> <li><span> </span></li> <li class="alt"> <span class="keyword">class</span><span> User </span><span class="keyword">implements</span><span> IUser </span> </li> <li><span>{ </span></li> <li class="alt"> <span> </span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> __construct( </span><span class="vars">$id</span><span> ) { } </span> </li> <li><span> </span></li> <li class="alt"> <span> </span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getName() </span> </li> <li><span> { </span></li> <li class="alt"> <span> </span><span class="keyword">return</span><span> </span><span class="string">"Jack"</span><span>; </span> </li> <li><span> } </span></li> <li class="alt"><span>} </span></li> <li><span> </span></li> <li class="alt"> <span class="keyword">class</span><span> UserFactory </span> </li> <li><span>{ </span></li> <li class="alt"> <span> </span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">function</span><span> Create( </span><span class="vars">$id</span><span> ) </span> </li> <li><span> { </span></li> <li class="alt"> <span> </span><span class="keyword">return</span><span> </span><span class="keyword">new</span><span> User( </span><span class="vars">$id</span><span> ); </span> </li> <li><span> } </span></li> <li class="alt"><span>} </span></li> <li><span> </span></li> <li class="alt"> <span class="vars">$uo</span><span> = UserFactory::Create( 1 ); </span> </li> <li> <span class="func">echo</span><span>( </span><span class="vars">$uo</span><span>->getName().</span><span class="string">"\n"</span><span> ); </span> </li> <li class="alt"><span>?> </span></li></span></li></ol>
The IUser interface defines what operations the user object should perform. The implementation of IUser is called User, and the UserFactory factory class creates IUser objects. This relationship can be represented by UML in Figure 1.
Figure 1. Factory class and its related IUser interface and user class
If you run this code on the command line using the php interpreter, you will get the following result:
<ol class="dp-c"> <li class="alt"><span><span>% php factory1.php </span></span></li> <li><span>Jack </span></li> <li class="alt"><span>% </span></li> </ol>
The test code will request the User object from the factory and output the result of the getName method.
There is a variant of the factory pattern that uses factory methods. These public static methods in a class construct objects of that type. This method is useful if it is important to create objects of this type. For example, suppose you need to create an object first and then set a number of properties. This version of the factory pattern encapsulates the process in a single location, so you don't have to copy complex initialization code and paste it all over the code base.
Example 2 shows an example of using factory methods.
<ol class="dp-c"><li class="alt"><span><span><?php </span></span><li> <span class="keyword">interface</span><span> IUser </span> </li> <li class="alt"><span>{ </span></li> <li> <span> </span><span class="keyword">function</span><span> getName(); </span> </li> <li class="alt"><span>} </span></li> <li><span> </span></li> <li class="alt"> <span class="keyword">class</span><span> User </span><span class="keyword">implements</span><span> IUser </span> </li> <li><span>{ </span></li> <li class="alt"> <span> </span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">function</span><span> Load( </span><span class="vars">$id</span><span> ) </span> </li> <li><span> { </span></li> <li class="alt"> <span> </span><span class="keyword">return</span><span> </span><span class="keyword">new</span><span> User( </span><span class="vars">$id</span><span> ); </span> </li> <li><span> } </span></li> <li class="alt"><span> </span></li> <li> <span> </span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">function</span><span> Create( ) </span> </li> <li class="alt"><span> { </span></li> <li> <span> </span><span class="keyword">return</span><span> </span><span class="keyword">new</span><span> User( null ); </span> </li> <li class="alt"><span> } </span></li> <li><span> </span></li> <li class="alt"> <span> </span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> __construct( </span><span class="vars">$id</span><span> ) { } </span> </li> <li><span> </span></li> <li class="alt"> <span> </span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getName() </span> </li> <li><span> { </span></li> <li class="alt"> <span> </span><span class="keyword">return</span><span> </span><span class="string">"Jack"</span><span>; </span> </li> <li><span> } </span></li> <li class="alt"><span>} </span></li> <li><span> </span></li> <li class="alt"> <span class="vars">$uo</span><span> = User::Load( 1 ); </span> </li> <li> <span class="func">echo</span><span>( </span><span class="vars">$uo</span><span>->getName().</span><span class="string">"\n"</span><span> ); </span> </li> <li class="alt"><span>?> </span></li></span></li></ol>
This code is much simpler. It has only one interface IUser and a User class that implements this interface. The User class has two static methods for creating objects. This relationship can be represented by UML in Figure 2.
Figure 2. IUser interface and user class with factory method
Running the script on the command line produces the same results as Listing 1, as follows:
<ol class="dp-c"> <li class="alt"><span><span>% php factory2.php </span></span></li> <li><span>Jack </span></li> <li class="alt"><span>% </span></li> </ol>
As mentioned above, sometimes such modes can seem overkill in smaller environments. However, it's best to learn this solid form of coding that you can apply to projects of any size.