实现功能:
依据类的cache属性,对数据表的读要缓存起来,对数据表的写需要清除缓存.
数据表根据属性字段来决定是否缓存
可以更换数据库链接方式,比如可以随时更换为mysql或mysqli()
当插入数据时给出一个通知或者提示,可以外部配置通知
一.数据操作接口
/**
* Interface db
*/
interface dbInterface
{
// 此处为简便起见,只定义读取所有记录和写入记录
public function all();
public function create(array $attributes);
}
二.数据库实现类(单例模式)
1.mysqli
class DbMySQLi implements dbInterface
{
private $link;
private static $instance;
private $table;
private function __construct()
{
$this->link = mysqli_connect('localhost', 'root', 'root', 'test');
}
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
public function setTable($table)
{
$this->table = $table;
}
/**
* @return array|null
*/
public function all()
{
$res = mysqli_query($this->link, "select * from {$this->table}");
$data = [];
while ($row = mysqli_fetch_assoc($res)) {
$data[] = $row;
}
return $data;
}
/**
* @param array $attributes
* @return bool|mysqli_result
*/
public function create(array $attributes)
{
$keys = array_keys($attributes);
$values = array_values($attributes);
foreach ($keys as $key => $val) {
$keys[$key] = "`{$val}`";
}
foreach ($values as $key => $val) {
$values[$key] = "'{$val}'";
}
$insertKey = implode(',', $keys);
$insertValue = implode(',', $values);
mysqli_query($this->link, "insert into {$this->table}($insertKey) values({$insertValue})");
return mysqli_insert_id($this->link);
}
public function closeLink()
{
if ($this->link) {
mysqli_close($this->link);
}
}
}
2.mysql
class DbMySQL implements dbInterface
{
private $link;
private static $instance;
private $table;
private function __construct()
{
$this->link = mysql_connect('localhost', 'root', 'root', 'test');
}
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
public function setTable($table)
{
$this->table = $table;
}
/**
* @return array|null
*/
public function all()
{
$res = mysql_query("select * from {$this->table}", $this->link);
$data = [];
while ($row = mysql_fetch_assoc($res)) {
$data[] = $row;
}
return $data;
}
/**
* @param array $attributes
* @return bool|mysqli_result
*/
public function create(array $attributes)
{
$keys = array_keys($attributes);
$values = array_values($attributes);
foreach ($keys as $key => $val) {
$keys[$key] = "`{$val}`";
}
foreach ($values as $key => $val) {
$values[$key] = "'{$val}'";
}
$insertKey = implode(',', $keys);
$insertValue = implode(',', $values);
mysql_query("insert into {$this->table}($insertKey) values({$insertValue})", $this->link);
return mysql_insert_id($this->link);
}
public function closeLink()
{
if ($this->link) {
mysql_close($this->link);
}
}
}
三.配置类
class Config
{
const DB_TYPE = 'mysql';
}
四.cache接口(适配器模式)
interface Cache
{
public function clearCache();
public function setCache($data);
public function getCache();
public function getKey();
}
文件缓存实现,此处用trait特性实现适配:
trait FileCacheTrait
{
public function clearCache()
{
@unlink($_SERVER['DOCUMENT_ROOT'] . '/cache-' . $this->getKey() . '.php');
}
public function setCache($data)
{
$file = $_SERVER['DOCUMENT_ROOT'] . '/cache-' . $this->getKey() . '.php';
$cache = '<?php' . "\n";
$cache .= 'return ';
$cache .= var_export($data, true);
$cache .= ';';
file_put_contents($file, $cache);
}
public function getCache()
{
$file = $_SERVER['DOCUMENT_ROOT'] . '/cache-' . $this->getKey() . '.php';
if (is_file($file)) {
return require $file;
}
return false;
}
public function getKey()
{
return md5($_SERVER['PHP_SELF'] . '?' . $_SERVER['QUERY_STRING']);
}
}
五.通知(观察者)
接口:
interface ObserverInterface
{
public function fire(Model $model);
}
实现:
class Observer implements ObserverInterface
{
public function fire(Model $model)
{
$model = $model->model();
echo "创建{$model->name}, id:{$model->id}";
}
}
六.Model虚拟类:通用数据操作
abstract class Model
{
protected $observers = []; //被观察者数组
protected $db;
protected $model;
protected $cache = false;
public function __construct()
{
// 简单工厂模式
if (Config::DB_TYPE == 'mysql') {
$this->db = DbMySQLi::getInstance($this->table());
} else {
$this->db = DbMySQL::getInstance($this->table());
}
$this->db->setTable($this->table());
}
public function all()
{
if ($this->cache && $cache = $this->getCache()) {
return $cache;
}
$data = $this->db->all();
if ($this->cache) {
$this->setCache($data);
}
return $data;
}
public function create(array $attributes)
{
$insertId = $this->db->create($attributes);
// 清除缓存
if ($this->cache) {
$this->clearCache();
}
$this->fill(array_merge($attributes, ['id' => $insertId]));
// 如果有设置created被观察者,直接调用
if (isset($this->observers['created'])) {
$this->observers['created']->fire($this);
}
return $insertId;
}
public function __destruct()
{
$this->db->closeLink();
}
public function addObserver($key, ObserverInterface $observer) {
$this->observers[$key] = $observer;
}
public function fill(array $attributes)
{
$this->model = (object) $attributes;
}
public function model()
{
return $this->model;
}
abstract public function table();
}
七.model实现类
class User extends Model implements Cache
{
// 配置缓存可用
protected $cache = true;
use FileCacheTrait;
public function table()
{
return 'user';
}
}
八.App类:从外部负责给model绑定被观察者
class App
{
public static function observer(Model $model)
{
$model->addObserver('created', new Observer($model));
}
}
调用:
$user = new User();
App::observer($user);
$user->create(['name' => 'test']);
附加:
如果要用闭包调用,则Model类对应部分改为:
// 如果有设置created被观察者,直接调用
if (isset($this->observers['created'])) {
if ($this->observers['created'] instanceof Closure) {
call_user_func($this->observers['created'], $this);
} else {
$this->observers['created']->fire($this);
}
}
App改为:
class App
{
public static function observer(Model $model)
{
$model->addObserver('created', function () use($model) {
echo "创建{$model->model()->name}, id:{$model->model()->id}";
});
}
}