我们再写一个Facade子类
class MyFacade extends Facade{
public static function getFacadeAccessor(){
return ServiceProvider::class;
}
}
这里注意,子类实现了父类没有具体实现的getFacadeAccessor方法,这个方法就是要告诉父类的__callstatic方法:“我作为Facade,代表的是什么哪个类,任务就由他来实现吧”,从语法上看,只是返回了一个表示类名的字符串。所以父类起初并不知道它的子类都代表着什么“服务提供者类”,只有当子类的静态函数被调用后,因为子类没有该静态函数,所以父类的__callstatic方法被启动了。
抽象工厂(Factory)
我对抽象工厂有一个粗俗的理解:“对象与字符串的对应”,也就是用一个字符串就可以创造一个类的对象。这种做法主要用在两种情况下是很方便的:
1.类名不稳定,会在项目中频繁修改
类名修改,很多时候并不是设计者的“命名洁癖”或者“命名强迫症”导致的修改,而是在项目的不断迭代,发觉这个类设计的不合理。如果这个类用的不频繁,那么改个类名只要手工做一些小的修改即可,但是如果这个类通篇存在于代码之中(假如是数据库类),那修改工作量就大了,当然,我们也可以对代码文件使用“字符串替换”,但是假如一个PHP写成的项目,PHP文件有几十上百个,这也是不合理的事。
2.类的设计者并不是类的使用者
类的设计者和类的使用者不是同一个开发人员,那么记忆一个字符串或许比记忆一个类名要生动的多。我们都学过计算机网络原理,都知道记忆一个域名要比记忆一个IP地址要生动的多,这就是DNS解决的问题。
因为抽象工厂很多教材都有涉及,不再赘述,本文将介绍一下目前非常流行的服务容器。
我们希望整个工程项目中,DB类,Session类,FileSystem类“拿来即用”,不用每次繁琐的初始化,比如写$db=new DB(arg1,arg2);这类语句,也希望DB等类型的对象像一个“全局”变量一般,在整个程序运行期间,随时可以调用。
服务容器可以让调用DB等类型的程序员不用知道这个类太多的细节,甚至可以用一个字符串的别名来创建这样一个对象。
我们定义一个服务容器类
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);
}
}
可以把服务容器简单的看成一个全局变量,bind方法就是用关联数组把字符串和构造函数做绑定。
至此,有了服务容器,我们的Model类就要做修改了
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);
}
}







