This article is the third article of homemade php framework,We mainly explain the use of php design patterns,In this article, let's learn the three most commonly used design patterns in PHP:singleton design pattern, factory design pattern, and observer design pattern.

Why use design patterns?

Design Patterns,My understanding is to achieve the goal of "reusability",And designed a set of cooperating classes.

Interested readers can read "design patterns:elements of reusable object-oriented software". The four authors (gang of four) list 23 industry-renowned design patterns in the book.

Here are three design patterns that our framework will cover.

Singleton pattern (singleton)

The singleton pattern can guarantee that a class has only one object instance, Commonly used in database access classes,Thus saving the consumption of hardware resources.

Here, we rewrite the mysql class from the previous chapter

class mysql extends db {
private static $instance=null;
public static function getinstance () {
if (self ::$instance == null) {
self ::$instance=new mysql ();
return self ::$instance;
public function mysql () {
/* config * /
/* end of config * /
$this->connection=mysqli_connect ($this->ip, $this->serverid, $this->serverpassword, $this-&databasename);
if (! $this->connection) {
die ("could not connect". $this->connection);
mysqli_query ($this->connection, "set names utf8");
public function execute ($sql) {
return mysqli_query ($this->connection, $sql);
public function query ($sql) {
$result=mysqli_query ($this->connection, $sql);
$arr=array ();
while ($row=mysqli_fetch_array ($result)) {
$arr []=$row;
return $arr;
public function close () {
mysqli_close ($this->connection);

The thing to note here is thatIf you instantiate a mysql class, we no longer write

$db=new mysql ();

But this:

$db=mysql ::getinstance ();

Because there is only the static function getinstance,Can guarantee that the constructor of the mysql class is called only once.

Singleton pattern is a very common design pattern,I won't repeat them here.

Appearance mode

Because of namespace issues,The appearance pattern can ensure that many methods of a class seem to be "provided by one class". Here we first design a simple service provider class

class serviceprovider {
public function write ($arg) {
echo $arg;

This class has only one write method, which is to print the parameters

Then define a facade class

class facade {
public static function getinstance ($classname, $args) {
return new $classname ($args);
public static function getfacadeaccessor () {
public static function __callstatic ($method, $args) {
$instance=static ::getinstance (static ::getfacadeaccessor (), $args);
return call_user_func_array (array ($instance, $method), $args);

To understand this class,We just focus on the last function,This is the __callstatic magic method.This method is when the facade type object or its subclass calls a function that has not been defined by itself,Will call the __callstatic method, and this method finally calls the call_user_func_array function, which is to leave the task to the class that provides this service to complete,At the same time, the parameters are passed.

We write another facade subclass

class myfacade extends facade {
public static function getfacadeaccessor () {
return serviceprovider ::class;

Note here,The child class implements the getfacadeaccessor method that the parent class does not implement. This method is to tell the parent class the __callstatic method:"As a facade, what class does it represent?Let him do the task. "From a grammatical perspective,Just returned a string representing the class name.So at first the parent class didn't know what "service provider class" its subclasses represented. Only after the static function of the subclass was called,Because the subclass does not have the static function,So the __callstatic method of the parent class is activated.

Abstract factory

I have a vulgar understanding of abstract factories:"correspondence between objects and strings", that is, a string of objects can be used to create a class of objects.This approach is convenient in two main cases:

1. The class name is unstable,Will be frequently modified in the project

Class name modification,In many cases, it is not a modification caused by the designer ’s "named cleanliness" or "named obsessive-compulsive disorder."But in the continuous iteration of the project,Found that the design of this class is unreasonable.If this class is used infrequently,Then changing the class name is as simple as making some small changes by hand,But if this class exists in the code throughout (if it is a database class), then the modification workload will be large,Of course, we can also use "string replacement" for the code file, but if a PHP project,There are dozens or hundreds of php files,This is also unreasonable.

2. The designer of the class is not the user of the class

The designer and user of the class are not the same developer.So remembering a string may be more vivid than remembering a class name.We have all learned the principles of computer networks,Everyone knows that remembering a domain name is more vivid than remembering an IP address.This is the problem that DNS solves.

Because many textbooks of the abstract factory are involved,No longer,This article will introduce the currently popular service containers.

We hope that throughout the project,db class, session class, filesystem class "get it and use it", no need for tedious initialization every time,For example, write $db=new db (arg1, arg2);I also hope that objects such as db are like a "global" variable.During the entire program,Can be called at any time.

The service container allows programmers who call types such as db to not have to know too much about this class.You can even create such an object with a string alias.

We define a service container class

class container {
public $bindings;
public function bind ($abstract, $concrete) {
$this->bindings [$abstract]=$concrete;
public function make ($abstract, $parameters=[]) {
return call_user_func_array ($this->bindings [$abstract], $parameters);

Think of the service container as a global variable.The bind method binds a string to a constructor using an associative array.

At this point, with the service container,Our model class needs to be modified

class model implements imodel {
public static $table;
public static $container;
public static $db;
public function __construct () {
self ::$container=new container ();
self ::$container->bind ("db", function () {
return mysql ::getinstance ();
self ::$db=self ::$container->make ("db", []);
public static function get ($id) {
return self ::where ("id", $id);
public static function where ($condition, $value) {
$sql=sprintf ("select * from%s where%s ="%s "", self ::$table, $condition, $value);
return self ::$db->query ($sql);
public static function all () {
$sql=sprintf ("select * from%s", self ::$table);
return self ::$db->query ($sql);

Looking at the code above,We used both the singleton pattern and the service container.

Summary:If i want to build a php framework, you should do code reuse.Design patterns have been the focus of much debate,"Why should I use design patterns?"I also try to avoid "too entangled with this problem", I think that design patterns have their value,At least in specific projects,It does save work in many version iterations,Improve work efficiency,But if in a small project I use design patterns for "show me how I will design patterns",Would be unreasonable.

  • Previous Timer and TimerTask examples in Java
  • Next Hibernate secondary cache in java