柔晶美网络工作室

柔晶美网络工作室,倾心于web技术的博客站点

关注我 微信公众号

您现在的位置是: 首页 > 博客日记

重构PHP通用查询系统之5----PDO操作MYSQL数据库的常用方法

2020-01-26 admin php  mysql  1441

作为PHP最佳搭档MYSQL,必须熟悉其基本的使用方法。mysqli方式大家都很熟悉了,而最新的PDO方式支持多种数据库,因接触少较不熟悉。这章我们来熟悉一下基本的操作:

首先是在config.php中放置数据库相关信息:

// 数据库配置
$config['db']['host'] = 'localhost';
$config['db']['username'] = 'pdo_dzbfsj_com';
$config['db']['password'] = 'pWRYwhMmhFjJwGPd';
$config['db']['dbname'] = 'pdo_dzbfsj_com';
// 默认控制器和操作名
$config['defaultController'] = 'Home';
$config['defaultAction'] = 'index';
return $config;

之后,在框架主程序Fastphp.php中初始化常量:

    // 配置数据库信息
    public function setDbConfig()
    {
        if ($this->config['db']) {
            define('DB_HOST', $this->config['db']['host']);
            define('DB_NAME', $this->config['db']['dbname']);
            define('DB_USER', $this->config['db']['username']);
            define('DB_PASS', $this->config['db']['password']);
        }
    }

然后在DB类中创建对象:

namespace fastphp\db;
use PDO;
use PDOException;
/**
 * 数据库操作类。
 * 其$pdo属性为静态属性,所以在页面执行周期内,
 * 只要一次赋值,以后的获取还是首次赋值的内容。
 * 这里就是PDO对象,这样可以确保运行期间只有一个
 * 数据库连接对象,这是一种简单的单例模式
 * Class Db
 */
class Db
{
    private static $pdo = null;
    public static function pdo()
    {
        if (self::$pdo !== null) {
            return self::$pdo;
        }
        try {
            $dsn    = sprintf('mysql:host=%s;dbname=%s;charset=utf8', DB_HOST, DB_NAME);
            $option = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC);
            return self::$pdo = new PDO($dsn, DB_USER, DB_PASS, $option);
        } catch (PDOException $e) {
            exit($e->getMessage());
        }
    }
}

现在可以在Sql.php中写上常用的读写查删数据库的方法了:

namespace fastphp\db;
use \PDOStatement;
class Sql
{
    // 数据库表名,pdo不支持绑定中文字段,因此需要判断是中文就用Md5
    protected $table;
    // 数据库主键
    protected $primary = 'id';
    // WHERE和ORDER拼装后的条件
    private $filter = '';
    // Pdo bindParam()绑定的参数集合
    private $param = array();
    /**
     * 查询条件拼接,使用方式:
     *
     * $this->where(['id = 1','and title="Web"', ...])->fetch();
     * 为防止注入,建议通过$param方式传入参数:
     * $this->where(['id = :id'], [':id' => $id])->fetch();
     * $this->where(['id = ?'], [$id])->fetch();
     * @param array $where 条件
     * @return $this 当前对象
     */
    public function where($where = array(), $param = array())
    {
        if ($where) {
            $this->filter = $this->filter.' WHERE ';
            $this->filter = $this->filter.implode(' ', $where);//把数组元素组合为一个字符串id=?,xmmc=?
            $this->param = $param;
        }
        return $this;
    }
    //直接传入关联数组查询
    public function wherearray($data = array())
    {
        if ($data) {
        $i = 0;
foreach($data as $key=>$val){
//转换为pdo查询语句
if($i == 0){
$fil[$i] = $key.' = ?';
}else{
$fil[$i] = 'and '.$key.' = ?';
}
$pal[$i] = $val;
$i++;
}
            $this->filter = $this->filter.' WHERE ';
            $this->filter = $this->filter.implode(' ', $fil);//把数组元素组合为一个字符串id=?,xmmc=?
            $this->param = $pal;
        }
        return $this;
    }
    /**
     * 拼装排序条件,使用方式:
     *
     * $this->order(['id DESC', 'title ASC', ...])->fetch();
     *
     * @param array $order 排序条件
     * @return $this
     */
    public function order($order = array())
    {
        if($order) {
            $this->filter .= ' ORDER BY ';
            $this->filter .= implode(',', $order);
        }
        return $this;
    }
    // 查询所有
    public function fetchAll()
    {
        $sql = sprintf("select * from `%s` %s", $this->table, $this->filter);
        $sth = Db::pdo()->prepare($sql);
        $sth = $this->formatParam($sth, $this->param);
        $sth->execute();
        return $sth->fetchAll();
    }
    // 查询一条
    public function fetch()
    {
        $sql = sprintf("select * from `%s` %s", $this->table, $this->filter);
        $sth = Db::pdo()->prepare($sql);
        $sth = $this->formatParam($sth, $this->param);
        $sth->execute();
        return $sth->fetch();
    }
    // 根据条件 (id) 删除
    public function delete($id)
    {
        $sql = sprintf("delete from `%s` where `%s` = :%s", $this->table, $this->primary, $this->primary);
        $sth = Db::pdo()->prepare($sql);
        $sth = $this->formatParam($sth, [$this->primary => $id]);
        $sth->execute();
        return $sth->rowCount();
    }
    // 新增一条数据,不支持中文字段
    public function add($data)
    {
        $sql = sprintf("insert into `%s` %s", $this->table, $this->formatInsert($data));
        $sth = Db::pdo()->prepare($sql);
        $sth = $this->formatParam($sth, $data);
        $sth = $this->formatParam($sth, $this->param);
        //var_dump($sth);exit;
        $sth->execute();
        return $sth->rowCount();
    }
    // 修改数据,不支持中文字段
    public function update($data)
    {
        $sql = sprintf("update `%s` set %s %s", $this->table, $this->formatUpdate($data), $this->filter);
        $sth = Db::pdo()->prepare($sql);
        $sth = $this->formatParam($sth, $data);
        $sth = $this->formatParam($sth, $this->param);
        //var_dump($sth);exit;
        $sth->execute();
        return $sth->rowCount();
    }
    /**
     * 占位符绑定具体的变量值
     * @param PDOStatement $sth 要绑定的PDOStatement对象
     * @param array $params 参数,有三种类型:
     * 1)如果SQL语句用问号?占位符,那么$params应该为
     *    [$a, $b, $c]
     * 2)如果SQL语句用冒号:占位符,那么$params应该为
     *    ['a' => $a, 'b' => $b, 'c' => $c]
     *    或者
     *    [':a' => $a, ':b' => $b, ':c' => $c]
     *
     * @return PDOStatement
     */
    public function formatParam(PDOStatement $sth, $params = array())
    {
        foreach ($params as $param => &$value) {
            $param = is_int($param) ? $param + 1 : ':' . ltrim($param, ':');
            $sth->bindParam($param, $value);
        }
        return $sth;
    }
    // 将数组转换成插入格式的sql语句
    private function formatInsert($data)
    {
        $fields = array();
        $names = array();
        foreach ($data as $key => $value) {
            $fields[] = sprintf("`%s`", $key);//sprintf格式化字符,两边加上`
            $names[] = sprintf(":%s", $key);//sprintf格式化字符,前面加上:
        }
        $field = implode(',', $fields);
        $name = implode(',', $names);
//(`id`,`姓名`,`身份证号`,`基本工资`,`奖励工资`,`其它`,`总计`) values 
//(:id,:姓名,:身份证号,:基本工资,:奖励工资,:其它,:总计)
        return sprintf("(%s) values (%s)", $field, $name);
    }
    // 将数组转换成更新格式的sql语句
    private function formatUpdate($data)
    {
        $fields = array();
        foreach ($data as $key => $value) {
//pdo不支持绑定中文字段
$key = str_replace('.', '_', $key);
if (preg_match("/[\x7f-\xff]/", $key)) {//add_判断字符串中是否有中文
$key2 = 'd'.time().'t';//随机命名
$fields[] = sprintf("`%s` = :%s", $key, $key2);
}else{
$fields[] = sprintf("`%s` = :%s", $key, $key);
}
        }
        return implode(',', $fields);
    }
}

这种绑定参数的方式操作数据库,是不支持中文字段的,因此,在Model中我们经常要写上自定义的方法,像删除插入一类的,可以使用pdo->exec方式,只返回成功执行受影响的行数,不返回数据。pdo支持批量插入数据,在此重构中,用到的自定义方法有:

namespace app\models;
use fastphp\base\Model;
use fastphp\db\Db;
/**
 * 创建临时表字段
 */
class Lssjb extends Model
{
    //创建bgsx初始表,表名为xmmc的md5值,字段有id,bm,xmmc,cxtj,kfcxzd,kftbzd,beizhu,cjrq的数据表
    public function create_table($bm, $zdsz){
    $sql = 'id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,';
    //将字段数组转成sql字段语句
    $num = count($zdsz) - 1;
    $i = 0;
    foreach($zdsz as $zd){
    if($i == $num){
    //最后一个,不加,
    $sql = $sql."`$zd` VARCHAR(255) NULL";
    }else{
    $sql = $sql."`$zd` VARCHAR(255) NULL,";
    }
    $i++;
    }
    $sql = "CREATE TABLE $bm ($sql)";
//使用 exec(),$fh = int(0) 时执行成功
$fh = Db::pdo()->exec($sql);
return $fh;
    }
//批量插入   
public function insert($table,$arrData) {
    $name = $values = '';
    $flag = $flagV = 1;
$true = is_array( current($arrData) );//判断是否一次插入多条数据
if($true) {
        //构建插入多条数据的sql语句
        foreach($arrData as $arr) {
            $values .= $flag ? '(' : ',(';
            foreach($arr as $key => $value) {
                if($flagV) {
                    if($flag) $name .= "$key";
                    $values .= "'$value'";
                    $flagV = 0;
                } else {
                    if($flag) $name .= ",$key";
                    $values .= ",'$value'";
                }
            }
            $values .= ') ';
            $flag = 0;
            $flagV = 1;
        }
} else {
        //构建插入单条数据的sql语句
        foreach($arrData as $key => $value) {
            if($flagV) {
                $name = "$key";
                $values = "('$value'";
                $flagV = 0;
            } else {
                $name .= ",$key";
                $values .= ",'$value'";
            }
        }
        $values .= ") ";
    }
$strSql = "insert into $table ($name) values $values";
$fh = Db::pdo()->exec($strSql);
if($fh > 0) {
        return true;
    }
return false;
}
//获取$table表的所有字段
public function hqsyzd($table){
$sql="SHOW COLUMNS FROM  `$table`";
$sth = Db::pdo()->prepare($sql);
        $sth->execute();
        while($result=$sth->fetch()){
$zdsz[] = $result['Field'];
}
return $zdsz;
}
//删除数据表
public function droptable($table){
$sql = "DROP TABLE $table";
$fh = Db::pdo()->exec($sql);
return $fh;
}
}

还有个通用的Model,数据表名和字段都不确定时使用:

namespace app\models;
use fastphp\base\Model;
use fastphp\db\Db;
/**
 * 通用Model
 */
class Table extends Model
{
//构造函数属性声明是由关键字 public,protected 或者 private 开头,然后跟一个普通的变量声明来组成。 
    protected $table;//创建属性
    public function __construct($bm)//接收控制器变量bm,在函数内部通过func_get_args()函数就可以取得所有传入的参数
    {
        $this->table = $bm;//赋值给table
    }
    // 修改数据,exec执行支持中文字段
    public function updateArray($where,$data)
    {
$sh = Db::pdo();
foreach($data as $k=>$v){
$zd = "`$k`";
$nr = $sh->quote($v);//过滤参数,自动加引号
}
$zdnr = "$zd = $nr";
$sql  = "UPDATE `$this->table` SET $zdnr WHERE $where";
$stmt = $sh->exec($sql);
        return $stmt;
    }
}

因对PDO很陌生,只记录用过的方法,待深入了解后再修改。

文章评论


需要 登录 才能发表评论
热门评论
0条评论

暂时没有评论!