实现功能:
对数据表的读要缓存起来,对数据表的写需要清除缓存.
数据表根据属性字段来决定是否缓存
可以更换数据库链接方式,比如可以随时更换为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}";
        });
    }
}
