从Laravel源码看PHP设计模式
SunDoge opened this issue · 0 comments
工厂模式
用工厂方法或者类来实例化对象,而不是直接new。
首先我们需要创建一个工厂类,比如Factory.php
。如果不使用工厂模式的,我们需要一个对象的时候通常需要
new Inexistence\girlfriend();
然而我们一般不只在一个地方需要这个对象,这个时候一旦对象发生变更,或者对象的某些属性发生变化,我们就需要一个一个的来改,非常麻烦。这个时候我们引入工厂类,在Factory.php
中
<?php
namespace Imagination;
class Factory
{
static function getGirlfriend()
{
$GF = new girlfriend;
return $GF;
}
}
然后每次调用时$GF1 = Imagination\Factory::getGirlfriend()
就可以避免四处修改的问题。
在Laravel中这样的设计模式很常见。
class CommentsController extends Controller {
/**
* Store a newly created resource in storage.
*
* @return Response
*/
public function store()
{
if (Comment::create(Input::all())) {
return Redirect::back();
} else {
return Redirect::back()->withInput()->withErrors('Fail to comment!');
}
}
}
单例模式
即确保某个类的对象仅被创建一次。比如我们在database里面存了很多女生的联系方式,如果我们用pdo的话每次查找都会new一个对象,势必会造成资源的浪费。所以我们就在connect之前做个判断。
class Database
{
static private $db;
private function __construct()
{
}
static function getInstance()
{
if (empty(self::$db)) {
self::$db = new self;
return self::$db;
} else {
return self::$db;
}
}
function where($where)
{
return $this;
}
function order($order)
{
return $this;
}
function limit($limit)
{
return $this;
}
function query($sql)
{
echo "SQL: $sql\n";
}
}
这里面比较关键的地方在于声明了一个私有变量和私有的构造方法,然后再在这个类里面new自己,就避免了在其他地方重复实例化的问题。这个时候我们已经没法直接new Database
了,我们只能通过调用get Instance
方法来建立连接。这里顺带讲一下PHP的链式操作的实现。在很多框架比如用完26个字母就不知道怎么办的thinkPHP和Laravel中对数据库的操作可以使用链式操作,这样可以使代码更为优雅。具体实现就是使用return this;
,这样就可以用where($where)->order($order)->limit(1);
来代替多行语句。
Laravel使用了三目运算符来代替if,显得更为优雅。
public function hasMany($related, $foreignKey = null, $localKey = null)
{
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related();
$localKey = $localKey ?: $this->getKeyName();
return new HasMany($instance->newQuery(), $this, $instance->getTable() . '.' . $foreignKey, $localKey);
}
注册模式
解决全局共享和交换对象的问题。实际上就是把实例好的对象放进一个数组,在任何地方要用的时候就去出来。就好比有一课树,我们把new好的$GF1,$GF2。。。一个一个挂上去,要用的时候再取出来。
class Register
{
protected static $objects;
/**
* 把对象映射到树上
* @param string $alias 对象的别名
* @param array $object 储存所有对象
*/
static function set($alias, $object)
{
self::$objects[$alias] = $object;
}
/**
* 把对象从树上移除
* @param string $alias 对象的别名
* @return [type] [description]
*/
function _unset($alias)
{
unset(self::$objects[$alias]);
}
}
unset
在PHP中是关键字,所以用_unset
代替。这样的话我们就要在工厂类中用一下Register::set()
方法,把new好的对象挂树上。为了调用方便,Register
中还需要一个get()
方法来取对象。
static function get($key)
{
if (!isset(self::$objects[$key]))
{
return false;
}
return self::$objects[$key];
}
这样我们也就不用再去使用单例模式了,直接从注册器中取Register::get()
。
Laravel中用了更优雅的方式。
<?php namespace Illuminate\Contracts\Auth;
interface Registrar {
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
public function validator(array $data);
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
public function create(array $data);
}
PHP还有很多有用的设计模式,比如观察者模式、代理模式、装饰器模式等,因为时间不够就不写了。有兴趣的可以自行了解。Laravel的源码遵循PSR规范,建议先了解再来看源码。