Ver código fonte

数据库类

walkor 11 anos atrás
pai
commit
8288ecd1c8

+ 25 - 0
applications/Demo/Config/Db.php

@@ -0,0 +1,25 @@
+<?php 
+namespace Config;
+
+/**
+ * mysql配置
+ * @author walkor
+ */
+class Db
+{
+    /**
+     * 数据库的一个实例配置,则使用时像下面这样使用
+     * $user_array = Db::instance('one_demo')->select('name,age')->from('user')->where('age>12')->query();
+     * 等价于
+     * $user_array = Db::instance('one_demo')->query('SELECT `name`,`age` FROM `one_demo` WHERE `age`>12');
+     * @var array
+     */
+    public static $one_demo = array(
+        'host'    => '127.0.0.1',
+        'port'    => 3306,
+        'user'    => 'mysql_user',
+        'password' => 'mysql_password',
+        'dbname'  => 'db_name',
+        'charset'    => 'utf8',
+    );
+}

+ 60 - 0
applications/Demo/Lib/Db.php

@@ -0,0 +1,60 @@
+<?php
+namespace Lib;
+/**
+ * 数据库类
+ * @author walkor <workerman.net>
+ */
+class Db
+{
+    /**
+     * 实例数组
+     * @var array
+     */
+    protected static $instance = array();
+    
+    /**
+     * 获取实例
+     * @param string $config_name
+     * @throws \Exception
+     */
+    public static function instance($config_name)
+    {
+        if(!isset(\Config\Store::$$config_name))
+        {
+            echo "\\Config\\Store::$config_name not set\n";
+            throw new \Exception("\\Config\\Store::$config_name not set\n");
+        }
+        
+        if(empty(self::$instance[$config_name]))
+        {
+            $config = \Config\Store::$$config_name;
+            self::$instance[$config_name] = new \Lib\DbConnection($config['host'], $config['port'], $config['user'], $config['password'], $config['db_name']');
+        }
+        return self::$instance[$config_name];
+    }
+    
+    /**
+     * 关闭数据库实例
+     * @param string $config_name
+     */
+    public static function close($config_name)
+    {
+        if(isset(self::$instance[$config_name]))
+        {
+            self::$instance[$config_name]->closeConnection();
+            self::$instance[$config_name] = null;
+        }
+    }
+    
+    /**
+     * 关闭所有数据库实例
+     */
+    public static function closeAll()
+    {
+        foreach(self::$instance as $connection)
+        {
+            $connection->closeConnection();
+            self::$instance = array();
+        }
+    }
+}

+ 1772 - 0
applications/Demo/Lib/DbConnection.php

@@ -0,0 +1,1772 @@
+<?php
+namespace Lib;
+
+class DbConnection 
+{
+    /**
+     * SELECT
+     * @var array
+     */
+    protected $union = array();
+    
+    /**
+     * 是否是更新
+     * @var bool
+     */
+    protected $for_update = false;
+    
+    /**
+     * 选择的列
+     * @var array
+     */
+    protected $cols = array();
+    
+    /**
+     * 从哪些表里面SELECT
+     * @var array
+     */
+    protected $from = array();
+    
+    /**
+     * $from 当前的 key
+     * @var int
+     */
+    protected $from_key = -1;
+    
+    /**
+     * GROUP BY 的列 
+     * @var array
+     */
+    protected $group_by = array();
+    
+    /**
+     * HAVING 条件数组.
+     * @var array
+     */
+    protected $having = array();
+    
+    /**
+     * HAVING 语句中绑定的值.
+     * @var array
+     */
+    protected $bind_having = array();
+    
+    /**
+     * 每页多少条记录
+     * @var int
+     */
+    protected $paging = 10;
+    
+    /**
+     * sql中绑定的值
+     * @var array
+     */
+    protected $bind_values = array();
+    
+    /**
+     * WHERE 条件.
+     * @var array
+     */
+    protected $where = array();
+    
+    /**
+     * WHERE语句绑定的值
+     * @var array
+     */
+    protected $bind_where = array();
+    
+    /**
+     * ORDER BY 的列
+     * @var array
+     */
+    protected $order_by = array();
+    
+    /**
+     * SELECT多少记录
+     * @var int
+     */
+    protected $limit = 0;
+    
+    /**
+     * 返回记录的游标
+     * @var int
+     */
+    protected $offset = 0;
+    
+    /**
+     * flags 列表
+     * @var array
+     */
+    protected $flags = array();
+    
+    /**
+     * 操作哪个表
+     * @var string
+     */
+    protected $table;
+   
+    /**
+     * 表.列 和 last-insert-id 映射
+     * @var array
+     */
+    protected $last_insert_id_names = array();
+    
+    /**
+     * INSERT 或者 UPDATE 的列 
+     * @param array
+     */
+    protected $col_values;
+    
+    /**
+     * 返回的列
+     * @var array
+     */
+    protected $returning = array();
+    
+    /**
+     * sql的类型 SELECT INSERT DELETE UPDATE
+     * @var string
+     */
+    protected $type = '';
+    
+    /**
+     * pdo 实例
+     * @var pdo
+     */
+    protected $pdo;
+    
+    /**
+     * PDO statement 实例
+     * @var PDO statement
+     */
+    protected $sQuery;
+    
+    /**
+     * 数据库用户名密码等配置
+     * @var array
+     */
+    protected $settings = array();
+    
+    /**
+     * sql的参数
+     * @var array
+     */
+    protected $parameters = array();
+    
+    /**
+     * 最后一条直行的sql
+     * @var string
+     */
+    protected $lastSql = '';
+
+    /**
+     * 选择哪些列
+     * @param string/array $cols
+     */
+    public function select($cols = '*')
+    {
+        $this->type = 'SELECT';
+        if(!is_array($cols))
+        {
+            $cols = array($cols);
+        }
+        $this->cols($cols);
+        return $this;
+    }
+    
+    /**
+     * 从哪个表删除
+     * @param string $table
+     * @return self
+     */
+    public function delete($table)
+    {
+        $this->type = 'DELETE';
+        $this->table = $this->quoteName($table);
+        $this->fromRaw($this->quoteName($table));
+        return $this;
+    }
+
+    /**
+     * 更新哪个表
+     * @param string $table
+     */
+    public function update($table)
+    {
+        $this->type = 'UPDATE';
+        $this->table = $this->quoteName($table);
+        return $this;
+    }
+
+    /**
+     * 向哪个表插入
+     * @param string $table
+     */
+    public function insert($table)
+    {
+        $this->type = 'INSERT';
+        $this->table = $this->quoteName($table);
+        return $this;
+    }
+    
+    /**
+     *
+     * 设置 SQL_CALC_FOUND_ROWS 标记.
+     * @param bool 
+     * @return self
+     */
+    public function calcFoundRows($enable = true)
+    {
+        $this->setFlag('SQL_CALC_FOUND_ROWS', $enable);
+        return $this;
+    }
+
+    /**
+     * 设置 SQL_CACHE 标记
+     * @param bool 
+     * @return self
+     */
+    public function cache($enable = true)
+    {
+        $this->setFlag('SQL_CACHE', $enable);
+        return $this;
+    }
+
+    /**
+     * 设置 SQL_NO_CACHE 标记
+     * @param bool
+     * @return self
+     */
+    public function noCache($enable = true)
+    {
+        $this->setFlag('SQL_NO_CACHE', $enable);
+        return $this;
+    }
+
+    /**
+     * 设置 STRAIGHT_JOIN 标记.
+     * @param bool
+     * @return self
+     */
+    public function straightJoin($enable = true)
+    {
+        $this->setFlag('STRAIGHT_JOIN', $enable);
+        return $this;
+    }
+
+    /**
+     * 设置 HIGH_PRIORITY 标记
+     * @param bool 
+     * @return self
+     */
+    public function highPriority($enable = true)
+    {
+        $this->setFlag('HIGH_PRIORITY', $enable);
+        return $this;
+    }
+
+    /**
+     * 设置 SQL_SMALL_RESULT 标记
+     * @param bool
+     * @return self
+     */
+    public function smallResult($enable = true)
+    {
+        $this->setFlag('SQL_SMALL_RESULT', $enable);
+        return $this;
+    }
+
+    /**
+     * 设置 SQL_BIG_RESULT 标记
+     * @param bool 
+     * @return self
+     */
+    public function bigResult($enable = true)
+    {
+        $this->setFlag('SQL_BIG_RESULT', $enable);
+        return $this;
+    }
+
+    /**
+     * 设置 SQL_BUFFER_RESULT 标记
+     * @param bool 
+     * @return self
+     */
+    public function bufferResult($enable = true)
+    {
+        $this->setFlag('SQL_BUFFER_RESULT', $enable);
+        return $this;
+    }
+    
+    /**
+     * 设置 FOR UPDATE 标记
+     * @param bool
+     * @return self
+     */
+    public function forUpdate($enable = true)
+    {
+        $this->for_update = (bool) $enable;
+        return $this;
+    }
+    
+    /**
+     * 设置 DISTINCT 标记
+     * @param bool
+     * @return self
+     */
+    public function distinct($enable = true)
+    {
+        $this->setFlag('DISTINCT', $enable);
+        return $this;
+    }
+    
+    /**
+     * 设置 LOW_PRIORITY 标记
+     * @param bool $enable
+     * @return self
+     */
+    public function lowPriority($enable = true)
+    {
+        $this->setFlag('LOW_PRIORITY', $enable);
+        return $this;
+    }
+    
+    /**
+     * 设置 IGNORE 标记
+     * @param bool $enable
+     * @return self
+     */
+    public function ignore($enable = true)
+    {
+        $this->setFlag('IGNORE', $enable);
+        return $this;
+    }
+    
+    /**
+     * 设置 QUICK 标记
+     * @param bool $enable
+     * @return self
+     */
+    public function quick($enable = true)
+    {
+        $this->setFlag('QUICK', $enable);
+        return $this;
+    }
+    
+    /**
+     * 设置 DELAYED 标记
+     * @param bool $enable
+     * @return self
+     */
+    public function delayed($enable = true)
+    {
+        $this->setFlag('DELAYED', $enable);
+        return $this;
+    }
+    
+    /**
+     * 序列化
+     * @return string 
+     */
+    public function __toString()
+    {
+        $union = '';
+        if ($this->union) {
+            $union = implode(' ', $this->union) . ' ';
+        }
+        return $union . $this->build();
+    }
+    
+    /**
+     * 设置每页多少条记录
+     * @param int 
+     * @return self
+     */
+    public function setPaging($paging)
+    {
+        $this->paging = (int) $paging;
+        return $this;
+    }
+    
+    /**
+     * 获取每页多少条记录
+     * @return int 
+     */
+    public function getPaging()
+    {
+        return $this->paging;
+    }
+    
+    /**
+     * 获取绑定在占位符上的值
+     */
+    public function getBindValues()
+    {
+        switch($this->type)
+        {
+            case 'SELECT':
+                return $this->getBindValuesSELECT();
+            case 'DELETE':
+            case 'UPDATE':
+            case 'INSERT':
+                return $this->getBindValuesCOMMON();
+            default :
+                throw new \Exception("type err");
+        }
+    }
+    
+    /**
+     * 获取绑定在占位符上的值
+     * @return array
+     */
+    public function getBindValuesSELECT()
+    {
+        $bind_values = $this->bind_values;
+        $i = 1;
+        foreach ($this->bind_where as $val) {
+            $bind_values[$i] = $val;
+            $i ++;
+        }
+        foreach ($this->bind_having as $val) {
+            $bind_values[$i] = $val;
+            $i ++;
+        }
+        return $bind_values;
+    }
+    
+    /**
+     *
+     * SELECT选择哪些列
+     * @param mixed
+     * @return null
+     */
+    protected function addColSELECT($key, $val)
+    {
+        if (is_string($key)) {
+            $this->cols[$val] = $key;
+        } else {
+            $this->addColWithAlias($val);
+        }
+    }
+    
+    /**
+     * SELECT增加选择的列
+     * @param string
+     * @return null
+     */
+    protected function addColWithAlias($spec)
+    {
+        $parts = explode(' ', $spec);
+        $count = count($parts);
+        if ($count == 2) {
+            $this->cols[$parts[1]] = $parts[0];
+        } elseif ($count == 3 && strtoupper($parts[1]) == 'AS') {
+            $this->cols[$parts[2]] = $parts[0];
+        } else {
+            $this->cols[] = $spec;
+        }
+    }
+    
+    /**
+     * from 哪个表
+     * @param string $table
+     * @return self
+     */
+    public function from($table)
+    {
+        return $this->fromRaw($this->quoteName($table));
+    }
+    
+    /**
+     * from的表
+     * @param string $table
+     * @return self
+     */
+    public function fromRaw($table)
+    {
+        $this->from[] = array($table);
+        $this->from_key ++;
+        return $this;
+    }
+    /**
+     *
+     * 子查询
+     * @param string $table
+     * @param string $name The alias name for the sub-select.
+     * @return self
+     */
+    public function fromSubSelect($table, $name)
+    {
+        $this->from[] = array( "($table) AS " . $this->quoteName($name));
+        $this->from_key ++;
+        return $this;
+    }
+    
+    
+    /**
+     * 增加join语句
+     * @param string $join  inner, left, natural
+     * @param string $table
+     * @param string $cond
+     * @return self
+     * @throws Exception
+     */
+    public function join($table, $cond = null, $type = '')
+    {
+    	return $this->joinInternal($type, $table, $cond);
+    }
+    
+    /**
+     * 增加join语句
+     * @param string $join  inner, left, natural
+     * @param string $table 
+     * @param string $cond 
+     * @return self
+     * @throws Exception
+     */
+    protected function joinInternal($join, $table, $cond = null)
+    {
+        if (! $this->from) {
+            throw new Exception('Cannot join() without from()');
+        }
+    
+        $join = strtoupper(ltrim("$join JOIN"));
+        $table = $this->quoteName($table);
+        $cond = $this->fixJoinCondition($cond);
+        $this->from[$this->from_key][] = rtrim("$join $table $cond");
+        return $this;
+    }
+    
+    /**
+     * quote
+     * @param string $cond 
+     * @return string
+     *
+     */
+    protected function fixJoinCondition($cond)
+    {
+        if (! $cond) {
+            return;
+        }
+    
+        $cond = $this->quoteNamesIn($cond);
+    
+        if (strtoupper(substr(ltrim($cond), 0, 3)) == 'ON ') {
+            return $cond;
+        }
+    
+        if (strtoupper(substr(ltrim($cond), 0, 6)) == 'USING ') {
+            return $cond;
+        }
+    
+        return 'ON ' . $cond;
+    }
+    
+    /**
+     * inner join
+     * @param string $spec
+     * @param string $cond 
+     * @return self
+     * @throws Exception
+     */
+    public function innerJoin($table, $cond = null)
+    {
+        return $this->joinInternal('INNER', $table, $cond);
+    }
+    
+    /**
+     * left join
+     * @param string $table
+     * @param string $cond 
+     * @return self
+     * @throws Exception
+     */
+    public function leftJoin($table, $cond = null)
+    {
+        return $this->joinInternal('LEFT', $table, $cond);
+    }
+    
+    /**
+     * right join
+     * @param string $table
+     * @param string $cond
+     * @return self
+     * @throws Exception
+     */
+    public function rightJoin($table, $cond = null)
+    {
+    	return $this->joinInternal('RIGHT', $table, $cond);
+    }
+    
+    /**
+     * joinSubSelect
+     * @param string $join  inner, left, natural
+     * @param string $spec
+     * @param string $name sub-select 的别名
+     * @param string $cond
+     * @return self
+     * @throws Exception
+     */
+    public function joinSubSelect($join, $spec, $name, $cond = null)
+    {
+        if (! $this->from) {
+            throw new Exception('Cannot join() without from() first.');
+        }
+    
+        $join = strtoupper(ltrim("$join JOIN"));
+        $name = $this->quoteName($name);
+        $cond = $this->fixJoinCondition($cond);
+        $this->from[$this->from_key][] = rtrim("$join ($spec) AS $name $cond");
+        return $this;
+    }
+    
+    /**
+     * group by 语句
+     * @param array $cols
+     * @return self
+     */
+    public function groupBy(array $cols)
+    {
+        foreach ($cols as $col) {
+            $this->group_by[] = $this->quoteNamesIn($col);
+        }
+        return $this;
+    }
+    
+    /**
+     * having 语句
+     * @param string $cond
+     * @return self
+     */
+    public function having($cond)
+    {
+        $this->addClauseCondWithBind('having', 'AND', func_get_args());
+        return $this;
+    }
+    
+    /**
+     * or having 语句
+     * @param string $cond The HAVING condition.
+     * @return self
+     */
+    public function orHaving($cond)
+    {
+        $this->addClauseCondWithBind('having', 'OR', func_get_args());
+        return $this;
+    }
+    
+    /**
+     * 设置每页的记录数量
+     * @param int $page 
+     * @return self
+     */
+    public function page($page)
+    {
+        $this->limit  = 0;
+        $this->offset = 0;
+    
+        $page = (int) $page;
+        if ($page > 0) {
+            $this->limit  = $this->paging;
+            $this->offset = $this->paging * ($page - 1);
+        }
+        return $this;
+    }
+    
+    /**
+     * union
+     * @return self
+     */
+    public function union()
+    {
+        $this->union[] = $this->build() . ' UNION';
+        $this->reset();
+        return $this;
+    }
+    
+    /**
+     * unionAll
+     * @return self
+     */
+    public function unionAll()
+    {
+        $this->union[] = $this->build() . ' UNION ALL';
+        $this->reset();
+        return $this;
+    }
+    
+    /**
+     * 重置
+     * @return null
+     */
+    protected function reset()
+    {
+        $this->resetFlags();
+        $this->cols       = array();
+        $this->from       = array();
+        $this->from_key   = -1;
+        $this->where      = array();
+        $this->group_by   = array();
+        $this->having     = array();
+        $this->order_by   = array();
+        $this->limit      = 0;
+        $this->offset     = 0;
+        $this->for_update = false;
+    }
+    
+    /**
+     * 清除所有数据
+     * @return void
+     */
+    protected function resetAll()
+    {
+        $this->union = array();
+        $this->for_update = false;
+        $this->cols = array();
+        $this->from = array();
+        $this->from_key = -1;
+        $this->group_by = array();
+        $this->having = array();
+        $this->bind_having = array();
+        $this->paging = 10;
+        $this->bind_values = array();
+        $this->where = array();
+        $this->bind_where = array();
+        $this->order_by = array();
+        $this->limit = 0;
+        $this->offset = 0;
+        $this->flags = array();
+        $this->table = '';
+        $this->last_insert_id_names = array();
+        $this->col_values = array();
+        $this->returning = array();
+        $this->parameters = array();
+    }
+    
+    /**
+     * 创建 SELECT SQL
+     * @return string
+     */
+    protected function buildSELECT()
+    {
+        return 'SELECT'
+        . $this->buildFlags()
+        . $this->buildCols()
+        . $this->buildFrom()
+        . $this->buildWhere()
+        . $this->buildGroupBy()
+        . $this->buildHaving()
+        . $this->buildOrderBy()
+        . $this->buildLimit()
+        . $this->buildForUpdate();
+    }
+    
+    /**
+     * 创建DELETE SQL
+     */
+    protected function buildDELETE()
+    {
+        return 'DELETE'
+            . $this->buildFlags()
+            . $this->buildFrom()
+            . $this->buildWhere()
+            . $this->buildOrderBy()
+            . $this->buildLimit()
+            . $this->buildReturning();
+    }
+
+    /**
+     * 生成SELECT列语句
+     * @return string
+     * @throws Exception
+     */
+    protected function buildCols()
+    {
+        if (! $this->cols) {
+            throw new Exception('No columns in the SELECT.');
+        }
+    
+        $cols = array();
+        foreach ($this->cols as $key => $val) {
+            if (is_int($key)) {
+                $cols[] = $this->quoteNamesIn($val);
+            } else {
+                $cols[] = $this->quoteNamesIn("$val AS $key");
+            }
+        }
+    
+        return $this->indentCsv($cols);
+    }
+    
+    /**
+     * 生成 FROM 语句.
+     * @return string
+     */
+    protected function buildFrom()
+    {
+        if (! $this->from) {
+            return '';
+        }
+    
+        $refs = array();
+        foreach ($this->from as $from) {
+            $refs[] = implode(' ', $from);
+        }
+        return ' FROM' . $this->indentCsv($refs);
+    }
+    
+    /**
+     * 生成 GROUP BY 语句.
+     * @return string
+     */
+    protected function buildGroupBy()
+    {
+        if (! $this->group_by) {
+            return ''; 
+        }
+        return ' GROUP BY' . $this->indentCsv($this->group_by);
+    }
+    
+    /**
+     * 生成 HAVING 语句.
+     * @return string
+     */
+    protected function buildHaving()
+    {
+        if (! $this->having) {
+            return ''; 
+        }
+        return ' HAVING' . $this->indent($this->having);
+    }
+    
+    /**
+     * 生成 FOR UPDATE 语句
+     * @return string
+     */
+    protected function buildForUpdate()
+    {
+        if (! $this->for_update) {
+            return ''; 
+        }
+        return ' FOR UPDATE';
+    }
+    
+    /**
+     * where
+     * @param string $cond 
+     * @param mixed ...$bind
+     * @return self
+     */
+    public function where($cond)
+    {
+    	if(is_array($cond))
+    	{
+    		foreach($cond as $key=>$val)
+    		{
+    			if(is_string($key))
+    			{
+    				$this->addWhere('AND', array($key, $val));
+    			}
+    			else
+    			{
+    				$this->addWhere('AND', array($val));
+    			}
+    		}
+    	}
+    	else 
+    	{
+        	$this->addWhere('AND', func_get_args());
+    	}
+        return $this;
+    }
+    
+    /**
+     * or where
+     * @param string $cond 
+     * @param mixed ...$bind
+     * @return self
+     */
+    public function orWhere($cond)
+    {
+    	if(is_array($con))
+    	{
+    		foreach($con as $key=>$val)
+    		{
+    			if(is_string($key))
+    			{
+    				$this->addWhere('OR', array($key, $val));
+    			}
+    			else
+    			{
+    				$this->addWhere('OR', array($val));
+    			}
+    		}
+    	}
+    	else
+    	{
+        	$this->addWhere('OR', func_get_args());
+    	}
+        return $this;
+    }
+    
+    /**
+     * limit 
+     * @param int $limit
+     * @return self
+     */
+    public function limit($limit)
+    {
+        $this->limit = (int) $limit;
+        return $this;
+    }
+    
+    /**
+     * limit offset
+     * @param int $offset 
+     * @return self
+     */
+    public function offset($offset)
+    {
+        $this->offset = (int) $offset;
+        return $this;
+    }
+    
+    /**
+     * orderby.
+     * @param array $cols
+     * @return self
+     */
+    public function orderBy(array $cols)
+    {
+        return $this->addOrderBy($cols);
+    }
+    
+    // -------------abstractquery----------
+    /**
+     * 返回逗号分隔的字符串
+     * @param array $list
+     * @return string
+     */
+    protected function indentCsv(array $list)
+    {
+        return ' ' . implode(',', $list);
+    }
+    
+    /**
+     * 返回空格分隔的字符串
+     * @param array $list
+     * @return string
+     */
+    protected function indent(array $list)
+    {
+        return ' ' . implode(' ', $list);
+    }
+    
+    /**
+     * 批量为占位符绑定值
+     * @param array $bind_values
+     * @return self
+     *
+     */
+    public function bindValues(array $bind_values)
+    {
+        foreach ($bind_values as $key => $val) {
+            $this->bindValue($key, $val);
+        }
+        return $this;
+    }
+    
+    /**
+     * 单个为占位符绑定值
+     * @param string $name 
+     * @param mixed $value
+     * @return self
+     */
+    public function bindValue($name, $value)
+    {
+        $this->bind_values[$name] = $value;
+        return $this;
+    }
+    
+    /**
+     * 生成flag
+     * @return string
+     */
+    protected function buildFlags()
+    {
+        if (! $this->flags) {
+            return '';
+        }
+        return ' ' . implode(' ', array_keys($this->flags));
+    }
+    
+    /**
+     * 设置 flag.
+     * @param string $flag 
+     * @param bool $enable
+     * @return null
+     */
+    protected function setFlag($flag, $enable = true)
+    {
+        if ($enable) {
+            $this->flags[$flag] = true;
+        } else {
+            unset($this->flags[$flag]);
+        }
+    }
+    
+    /**
+     * 重置flag
+     * @return null
+     */
+    protected function resetFlags()
+    {
+        $this->flags = array();
+    }
+    
+    /**
+     *
+     * 添加where语句
+     * @param string $andor 'AND' or 'OR
+     * @param array $conditions
+     * @return self
+     *
+     */
+    protected function addWhere($andor, $conditions)
+    {
+        $this->addClauseCondWithBind('where', $andor, $conditions);
+        return $this;
+    }
+    
+    /**
+     * 添加条件和绑定值
+     * @param string $clause where 、having等
+     * @param string $andor AND、OR等
+     * @param array $conditions 
+     * @return null
+     */
+    protected function addClauseCondWithBind($clause, $andor, $conditions)
+    {
+        $cond = array_shift($conditions);
+        $cond = $this->quoteNamesIn($cond);
+    
+        $bind =& $this->{"bind_{$clause}"};
+        foreach ($conditions as $value) {
+            $bind[] = $value;
+        }
+    
+        $clause =& $this->$clause;
+        if ($clause) {
+            $clause[] = "$andor $cond";
+        } else {
+            $clause[] = $cond;
+        }
+    }
+    
+    /**
+     * 生成where语句
+     * @return string
+     */
+    protected function buildWhere()
+    {
+        if (! $this->where) {
+            return ''; 
+        }
+        return ' WHERE' . $this->indent($this->where);
+    }
+    
+    /**
+     * 增加order by
+     * @param array $spec The columns and direction to order by.
+     * @return self
+     */
+    protected function addOrderBy(array $spec)
+    {
+        foreach ($spec as $col) {
+            $this->order_by[] = $this->quoteNamesIn($col);
+        }
+        return $this;
+    }
+    
+    /**
+     * 生成order by 语句
+     * @return string
+     */
+    protected function buildOrderBy()
+    {
+        if (! $this->order_by) {
+            return ''; 
+        }
+        return ' ORDER BY' . $this->indentCsv($this->order_by);
+    }
+    
+    /**
+     * 生成limit语句
+     * @return string
+     */
+    protected function buildLimit()
+    {
+        $has_limit = $this->type == 'DELETE' || $this->type == 'UPDATE';
+        $has_offset = $this->type == 'SELECT';
+    
+        if ($has_offset && $this->limit) {
+            $clause = " LIMIT {$this->limit}";
+            if ($this->offset) {
+                $clause .= " OFFSET {$this->offset}";
+            }
+            return $clause;
+        } elseif ($has_limit && $this->limit) {
+            return " LIMIT {$this->limit}";
+        }
+        return ''; 
+    }
+
+    /**
+     * Quotes 
+     * @param string $spec
+     * @return string|array 
+     */
+    public function quoteName($spec)
+    {
+        $spec = trim($spec);
+        $seps = array(' AS ', ' ', '.');
+        foreach ($seps as $sep) {
+            $pos = strripos($spec, $sep);
+            if ($pos) {
+                return $this->quoteNameWithSeparator($spec, $sep, $pos);
+            }
+        }
+        return $this->replaceName($spec);
+    }
+
+    /**
+     * 指定分隔符的Quotes 
+     * @param string $spec 
+     * @param string $sep 
+     * @param string $pos 
+     * @return string 
+     */
+    protected function quoteNameWithSeparator($spec, $sep, $pos)
+    {
+        $len = strlen($sep);
+        $part1 = $this->quoteName(substr($spec, 0, $pos));
+        $part2 = $this->replaceName(substr($spec, $pos + $len));
+        return "{$part1}{$sep}{$part2}";
+    }
+
+    /**
+     * Quotes "table.col" 格式的字符串
+     * @param string $text 
+     * @return string|array 
+     */
+    public function quoteNamesIn($text)
+    {
+        $list = $this->getListForQuoteNamesIn($text);
+        $last = count($list) - 1;
+        $text = null;
+        foreach ($list as $key => $val) {
+            if (($key+1) % 3) {
+                $text .= $this->quoteNamesInLoop($val, $key == $last);
+            }
+        }
+        return $text;
+    }
+
+    /**
+     * 返回quote元素列表
+     * @param string $text 
+     * @return array
+     */
+    protected function getListForQuoteNamesIn($text)
+    {
+        $apos = "'";
+        $quot = '"';
+        return preg_split(
+            "/(($apos+|$quot+|\\$apos+|\\$quot+).*?\\2)/",
+            $text,
+            -1,
+            PREG_SPLIT_DELIM_CAPTURE
+        );
+    }
+
+    /**
+     * 循环quote
+     * @param string $val 
+     * @param bool $is_last
+     * @return string 
+     */
+    protected function quoteNamesInLoop($val, $is_last)
+    {
+        if ($is_last) {
+            return $this->replaceNamesAndAliasIn($val);
+        }
+        return $this->replaceNamesIn($val);
+    }
+
+    /**
+     *
+     * 替换成别名
+     * @param string $val 
+     * @return string
+     */
+    protected function replaceNamesAndAliasIn($val)
+    {
+        $quoted = $this->replaceNamesIn($val);
+        $pos = strripos($quoted, ' AS ');
+        if ($pos) {
+            $alias = $this->replaceName(substr($quoted, $pos + 4));
+            $quoted = substr($quoted, 0, $pos) . " AS $alias";
+        }
+        return $quoted;
+    }
+
+    /**
+     * Quotes name 
+     * @param string $name 
+     * @return string 
+     */
+    protected function replaceName($name)
+    {
+        $name = trim($name);
+        if ($name == '*') {
+            return $name;
+        }
+        return '`'. $name.'`';
+    }
+
+    /**
+     * Quotes 
+     * @param string $text
+     * @return string|array 
+     */
+    protected function replaceNamesIn($text)
+    {
+        $is_string_literal = strpos($text, "'") !== false
+                        || strpos($text, '"') !== false;
+        if ($is_string_literal) {
+            return $text;
+        }
+
+        $word = "[a-z_][a-z0-9_]+";
+
+        $find = "/(\\b)($word)\\.($word)(\\b)/i";
+
+        $repl = '$1`$2`.`$3`$4';
+
+        $text = preg_replace($find, $repl, $text);
+
+        return $text;
+    }
+    
+     // ---------- insert --------------
+    /**
+     * 设置 `table.column` 与 last-insert-id 的映射
+     * @param array $insert_id_names
+     */
+    public function setLastInsertIdNames(array $last_insert_id_names)
+    {
+        $this->last_insert_id_names = $last_insert_id_names;
+    }
+
+    /**
+     * insert into.
+     * @param string $into
+     * @return self
+     */
+    public function into($table)
+    {
+        $this->table = $this->quoteName($table);
+        return $this;
+    }
+
+    /**
+     * 生成INSERT 语句
+     * @return string
+     */
+    protected function buildINSERT()
+    {
+        return 'INSERT'
+            . $this->buildFlags()
+            . $this->buildInto()
+            . $this->buildValuesForInsert()
+            . $this->buildReturning();
+    }
+
+    /**
+     * 生成 INTO 语句
+     * @return string
+     */
+    protected function buildInto()
+    {
+        return " INTO " . $this->table;
+    }
+
+    /**
+     * PDO::lastInsertId()
+     * @param string $col 
+     * @return mixed 
+     */
+    public function getLastInsertIdName($col)
+    {
+        $key = str_replace('`', '', $this->table) . '.' . $col;
+        if (isset($this->last_insert_id_names[$key])) {
+            return $this->last_insert_id_names[$key];
+        }
+    }
+
+    /**
+     *
+     * 设置一列,如果有第二各参数,则把第二个参数绑定在占位符上
+     * @param string $col 
+     * @param mixed  $val
+     * @return self
+     */
+    public function col($col)
+    {
+        return call_user_func_array(array($this, 'addCol'), func_get_args());
+    }
+
+    /**
+     * 设置多列
+     * @param array $cols 
+     * @return self
+     */
+    public function cols(array $cols)
+    {
+        if($this->type == 'SELECT')
+        {
+            foreach ($cols as $key => $val) 
+            {
+                $this->addColSELECT($key, $val);
+            }
+            return $this;
+        }
+        return $this->addCols($cols);
+    }
+
+    /**
+     * 直接设置列的值
+     * @param string $col
+     * @param string $value
+     * @return self
+     */
+    public function set($col, $value)
+    {
+        return $this->setCol($col, $value);
+    }
+
+    /**
+     * 为INSERT语句绑定值
+     * @return string
+     */
+    protected function buildValuesForInsert()
+    {
+        return ' ('.$this->indentCsv(array_keys($this->col_values)).') VALUES (' . $this->indentCsv(array_values($this->col_values)) . ')';
+    }
+
+    // ------update-------
+    /**
+     * 更新哪个表
+     * @param string $table
+     * @return self
+     */
+    public function table($table)
+    {
+        $this->table = $this->quoteName($table);
+        return $this;
+    }
+
+    /**
+     * 生成完整SQL语句
+     * @return string
+     */
+    protected function build()
+    {
+        switch($this->type)
+        {
+           case 'DELETE':
+             return $this->buildDELETE();
+           case 'INSERT':
+             return $this->buildINSERT();
+           case 'UPDATE':
+             return $this->buildUPDATE();
+           case 'SELECT':
+             return $this->buildSELECT();
+        }
+        throw new \Exception("type empty");
+    }
+    
+    /**
+     * 生成更新的SQL语句
+     */
+    protected function buildUPDATE()
+    {
+        return 'UPDATE'
+            . $this->buildFlags()
+            . $this->buildTable()
+            . $this->buildValuesForUpdate()
+            . $this->buildWhere()
+            . $this->buildOrderBy()
+            . $this->buildLimit()
+            . $this->buildReturning();
+   
+    }
+
+    /**
+     * 哪个表
+     * @return null
+     */
+    protected function buildTable()
+    {
+        return " {$this->table}";
+    }
+
+    /**
+     * 为更新语句绑定值
+     * @return string
+     */
+    protected function buildValuesForUpdate()
+    {
+        $values = array();
+        foreach ($this->col_values as $col => $value) {
+            $values[] = "{$col} = {$value}";
+        }
+        return ' SET' . $this->indentCsv($values);
+    }
+   
+    // ----------Dml---------------
+    /**
+     * 获取绑定的值
+     * @return array
+     */
+    public function getBindValuesCOMMON()
+    {
+        $bind_values = $this->bind_values;
+        $i = 1;
+        foreach ($this->bind_where as $val) {
+            $bind_values[$i] = $val;
+            $i ++;
+        }
+        return $bind_values;
+    }
+
+    /**
+     * 设置列
+     * @param string $col
+     * @param mixed $val
+     * @return self
+     */
+    protected function addCol($col)
+    {
+        $key = $this->quoteName($col);
+        $this->col_values[$key] = ":$col";
+        $args = func_get_args();
+        if (count($args) > 1) {
+            $this->bindValue($col, $args[1]);
+        }
+        return $this;
+    }
+
+    /**
+     * 设置多个列
+     * @param array $cols
+     * @return self
+     */
+    protected function addCols(array $cols)
+    {
+        foreach ($cols as $key => $val) {
+            if (is_int($key)) {
+                $this->addCol($val);
+            } else {
+                $this->addCol($key, $val);
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * 设置单列的值
+     * @param string $col .
+     * @param string $value
+     * @return self
+     */
+    protected function setCol($col, $value)
+    {
+        if ($value === null) {
+            $value = 'NULL';
+        }
+
+        $key = $this->quoteName($col);
+        $value = $this->quoteNamesIn($value);
+        $this->col_values[$key] = $value;
+        return $this;
+    }
+
+    /**
+     * 增加返回的列
+     * @param array $cols
+     * @return self
+     *
+     */
+    protected function addReturning(array $cols)
+    {
+        foreach ($cols as $col) {
+            $this->returning[] = $this->quoteNamesIn($col);
+        }
+        return $this;
+    }
+
+    /**
+     * 生成 RETURNING 语句
+     * @return string
+     */
+    protected function buildReturning()
+    {
+        if (! $this->returning) {
+            return '';
+        }
+        return ' RETURNING' . $this->indentCsv($this->returning);
+    }
+    
+    /**
+     * 构造函数
+     */
+    public function __construct($host, $port, $user, $password, $db_name, $charset = 'utf8')
+    {
+        $this->settings = array(
+            'host'          => $host,
+            'port'          => $port,
+            'user'          => $user,
+            'password' => $password,
+            'dbname'  => $db_name,
+            'charset'    => $charset,
+        );
+        $this->connect();
+    }
+    
+    /**
+     * 创建pdo实例
+     */
+    protected function connect()
+    {
+        $dsn = 'mysql:dbname='.$this->settings["dbname"].';host='.$this->settings["host"].';port='.$this->settings['port'];
+        $this->pdo = new PDO($dsn, $this->settings["user"], $this->settings["password"], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . (!empty($this->settings['charset']) ? $this->settings['charset'] : 'utf8')));
+        $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+        $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
+    }
+    /*
+    *   关闭连接
+    */
+    public function closeConnection()
+    {
+        $this->pdo = null;
+    }
+
+    /**
+     * 执行
+     * @param string $query
+     * @param string $parameters
+     */
+    protected function execute($query,$parameters = "")
+    {
+        try {
+            $this->sQuery = $this->pdo->prepare($query);
+            $this->bindMore($parameters);
+            if(!empty($this->parameters)) {
+                foreach($this->parameters as $param)
+                {
+                    $parameters = explode("\x7F",$param);
+                    $this->sQuery->bindParam($parameters[0],$parameters[1]);
+                }
+            }
+            $this->succes  = $this->sQuery->execute();
+        }
+        catch(\PDOException $e)
+        {
+            // 服务端断开时重连一次
+            if($e->errorInfo[1] == 2006 || $e->errorInfo[1] == 2013)
+            {
+                $this->closeConnection();
+                $this->connect();
+                $this->sQuery = $this->pdo->prepare($query);
+                $this->bindMore($parameters);
+                if(!empty($this->parameters)) {
+                    foreach($this->parameters as $param)
+                    {
+                        $parameters = explode("\x7F",$param);
+                        $this->sQuery->bindParam($parameters[0],$parameters[1]);
+                    }
+                }
+                $this->succes  = $this->sQuery->execute();
+            }
+            else
+            {
+                throw $e;
+            }
+        }
+        $this->parameters = array();
+    }
+    
+    /**
+    * 绑定
+    * @param string $para
+    * @param string $value
+    */
+    public function bind($para, $value)
+    {
+    	if(is_string($para))
+    	{
+        	$this->parameters[sizeof($this->parameters)] = ":" . $para . "\x7F" . $value;
+    	}
+    	else
+    	{
+    		$this->parameters[sizeof($this->parameters)] = $para . "\x7F" . $value;
+    	}
+    }
+    
+    /**
+     * 绑定多个
+     * @param array $parray
+     */
+    public function bindMore($parray)
+    {
+        if(empty($this->parameters) && is_array($parray)) {
+            $columns = array_keys($parray);
+            foreach($columns as $i => &$column)    {
+                $this->bind($column, $parray[$column]);
+            }
+        }
+    }
+    
+    /**
+     * 执行SQL
+     * @param  string $query
+     * @param  array  $params
+     * @param  int    $fetchmode
+     * @return mixed
+     */
+    public function query($query = '',$params = null, $fetchmode = PDO::FETCH_ASSOC)
+    {
+        $query = trim($query);
+        if(empty($query))
+        {
+            $query = $this->build();
+        }
+        if(!$params)
+        {
+            $params = $this->getBindValues();
+        }
+        $this->resetAll();
+        $this->lastSql = $query;
+        
+        $this->execute($query,$params);
+        
+        $rawStatement = explode(" ", $query);
+            
+        $statement = strtolower(trim($rawStatement[0]));
+        if ($statement === 'select' || $statement === 'show') {
+            return $this->sQuery->fetchAll($fetchmode);
+        }
+        elseif ( $statement === 'insert' ||  $statement === 'update' || $statement === 'delete' ) {
+            return $this->sQuery->rowCount();
+        }
+        else {
+            return NULL;
+        }
+    }
+    
+    /**
+    * 返回一列
+    * @param  string $query
+    * @param  array  $params
+    * @return array
+    */
+    public function column($query = '',$params = null)
+    {
+        $query = trim($query);
+        if(empty($query))
+        {
+            $query = $this->build();
+        }
+        if(!$params)
+        {
+            $params = $this->getBindValues();
+        }
+        $this->resetAll();
+        $this->lastSql = $query;
+        
+        $this->execute($query,$params);
+        $columns = $this->sQuery->fetchAll(PDO::FETCH_NUM);
+        $column = null;
+        foreach($columns as $cells) {
+            $column[] = $cells[0];
+        }
+        return $column;
+    }
+    
+    /**
+    * 返回一行
+    * @param  string $query
+    * @param  array  $params
+    * @param  int    $fetchmode
+    * @return array
+    */
+    public function row($query = '',$params = null, $fetchmode = PDO::FETCH_ASSOC)
+    {
+        $query = trim($query);
+        if(empty($query))
+        {
+            $query = $this->build();
+        }
+        if(!$params)
+        {
+            $params = $this->getBindValues();
+        }
+        $this->resetAll();
+        $this->lastSql = $query;
+        
+        $this->execute($query,$params);
+        return $this->sQuery->fetch($fetchmode);
+    }
+    
+    /**
+    * 返回单个值
+    * @param  string $query
+    * @param  array  $params
+    * @return string
+    */
+    public function single($query = '',$params = null)
+    {
+        $query = trim($query);
+        if(empty($query))
+        {
+            $query = $this->build();
+        }
+        if(!$params)
+        {
+            $params = $this->getBindValues();
+        }
+        $this->resetAll();
+        $this->lastSql = $query;
+        
+        $this->execute($query,$params);
+        return $this->sQuery->fetchColumn();
+    }
+    
+    /**
+     * 返回lastInsertId
+     * @return string
+     */
+    public function lastInsertId() {
+        return $this->pdo->lastInsertId();
+    }
+    
+    /**
+     * 返回最后一条直行的sql
+     * @return  string
+     */
+    public function lastSQL()
+    {
+        return $this->lastSql;
+    }
+}