在PHP的面向过程中,我们可以通过封装函数来实现对数据库的操作,那么在面向过程中,我们同样可以通过类来实现对数据库的操作,整个过程和面向过程的思路大体差不多,但是代码量更多了一些,实现起来稍微困难。一共实现了十个功能。先定义成员属性,然后定义成员方法。一共分为连接数据库的config文件、具体实现对数据库操作的类文件、测试代码。所有的代码均是通过了测试,具体的测试结果由于篇幅问题没有附图。
具体实现功能:
1、连接数据库;
2、插入数据;
3、更新数据;
4、删除数据;
5、修改数据;
6、求最大值;
7、求最小值;
8、求平均数;
9、求和;
10、指定查询;
具体代码分为三个部分:
一、config文件:主要用于连接数据库
<?php
return array(
'DB_HOST' => '127.0.0.1', //主机
'DB_USER' => 'root', //用户名
'DB_PWD' => '123456', //密码
'DB_NAME' => 'blog', //数据库名
'DB_CHARSET' => 'utf8', //字符集
'DB_PREFIX' => 'bbs_', //前缀
);
二、数据库操作类:
<?php
class UserModel
{
//链接
protected $link;
//主机
protected $host;
//数据库名字
protected $dbName;
//字符集
protected $charset;
//表名
protected $table;
//用户名
protected $user;
//密码
protected $pwd;
//表前缀
protected $prefix;
//字段
protected $fields;
//保存的查询、更新、添加的参数
protected $options;
//初始化数据库
public function __construct(Array $config)
{
//把一批成员属性都初始化
$this->host = $config['DB_HOST'];
$this->user = $config['DB_USER'];
$this->pwd = $config['DB_PWD'];
$this->dbName = $config['DB_NAME'];
$this->charset = $config['DB_CHARSET'];
$this->prefix = $config['DB_PREFIX'];
//连接
$this->link = $this->connect();
//判断连接成功与否 失败处理
if (!$this->link) {
exit('数据库连接或者选择数据库失败。');
}
//表名 需要处理
$this->table = $this->getTable();
//字段 需要处理
$this->fields = $this->getFields();
}
//连接数据库成员方法
protected function connect()
{
$conn = mysqli_connect($this->host,$this->user,$this->pwd);
//连接数据库失败处理
if (!$conn) {
return flase;
}
//选择数据失败处理
if (!mysqli_select_db($conn,$this->dbName)) {
return false ;
}
//设置字符集
mysqli_set_charset($conn,$this->charset);
//返回处理结果
return $conn;
}
//初始化表 【暂时出现报错,后面用命名空间解决】
protected function getTable()
{
//判断用户时候设置过?
if (isset($this->table)) {
//设置过就以用户的为准,先把用户前缀弃掉,然后拼接前缀,保证统一性
return $this->prefix . ltrim($this->table,$this->prefix);
} else {
//没有设置过就用 类名拼接前缀,组成一个全新的的表名
//get_class() 获取类名 等同于 __CLASS__
//获取类名后进行字串提取[substr( string,start,length )],并且全部转换为小写[strtolower()]
return $this->prefix . strtolower(substr(get_class($this),0,-5));
}
}
//初始化字段 需要把字段缓存到一个文件里面去
protected function getFields()
{
//如果有字段的文件说明以前缓存过这个文件,直接包含即可,但是需要知道文件路径的规则
//定义文件路径
$filePath = './caceh/' . $this->table . '.php';
//判断时候有缓存文件
if (file_exists($filePath)) {
//存在缓存文件直接包含即可
return include $filePath;
} else {
//没有的话就需要生成一个缓存文件
//首先需要查询字段
$fields = $this->queryFields();
//var_export() 输出或返回一个变量的字符串 true表示不打印 将其保存下来
$str = "<?php \n return ". var_export($fields,true) . ';?>';
//写入到缓存文件file_put_contents(文件保存路径,需要写进去的内容)
file_put_contents($filePath, $str);
}
return $fields;
}
//查询字段处理
protected function queryFields()
{
//打印字段的sql语句
$sql = 'desc ' . $this->table;
//var_dump($sql);
//执行sql语句 需要定义成员方法query
$data = $this->query($sql);
$fields = [];
//想要获取字段,需要对返回的数据进行遍历
foreach ($data as $key => $value) {
$fields[] = $value['Field'];
if ($value['Key'] == 'PRI') {
$fields['_pk'] = $value['Field'];
}
}
return $fields;
}
//系统级查询(定义为 public ),在外部调用的时候,想自定义SQL语句可以只是调用该成员方法
//查询相应的结果,这个仅供读取使用查询相应的结果
public function query($sql)
{
//执行一条SQL语句
$result = mysqli_query($this->link,$sql);
if ($result) {
$data = [];
//获取每行数据
while ($row = mysqli_fetch_assoc($result)) {
$data[] = $row;
}
return $data;
} else {
return false;
}
}
//查询成员方法
//准备好无需换的SQL语句
//用户调用询的时候,将call里面保存进去的参数,一一替换sql语句
//发送SQL语句
//返回查询的结果
public function select()
{
//拼接sql语句
$sql = "select %FIELDS% from %TABLE% %WHERE% %GROUP% %HAVING% %ORDER% %LIMIT%";
//将sql语句中的相应部分替换
$newsql = str_replace(
array(
'%FIELDS%',
'%TABLE%',
'%WHERE%',
'%GROUP%',
'%HAVING%',
'%ORDER%',
'%LIMIT%',
),
array(
$this->parseFields(),
$this->parseTable(),
$this->parseWhere(),
$this->parseGroup(),
$this->parseHaving(),
$this->parseOrder(),
$this->parseLimit(),
),
$sql
);
echo $newsql;
$this->sql = $newsql;
return $this->query($newsql);
}
//字段处理
protected function parseFields()
{
//因为我们对比字段的时不需要对比主键是谁,所以需要unset()
//将当前的字段赋值给一个变量
$fields = $this->fields;
unset($fields['_pk']);
//判断字段是什么形式(字符串、数组)
if (is_array($this->options['fields'][0])) {
//遍历取出键值
foreach ($this->options['fields'][0] as $key => $value) {
//判断传入的字段时候合法(属于表结构中的字段)
if (!in_array($value, $fields)) {
//如果不属于合法的字段就unset()
unset($this->options['fields'][0][$key]);
}
}
return join(',',$this->options['fields'][0]);
} else if (is_string($this->options['fields'][0])){
//如果是字符串就先变为数组进行处理
$this->options['fields'][0] = explode(',', $this->options['fields'][0]);
//遍历
foreach ($this->options['fields'][0] as $key => $value) {
//判断字段是否合法
if (!in_array($value,$fields)) {
unset($this->options['fields'][0][$key]);
}
return join(',',$this->options['fields'][0]);
}
} else {
return join(',',$fields);
}
}
//判断用户有没有手动指定过查询哪个用
//如果指定过,则以用户设定的options里面的表为准
//如果没有设定过,则以默认的为准
protected function parseTable()
{
if (isset($this->options['table'][0])) {
return $this->options['table'][0];
} else {
return $this->table;
}
}
//判断用户设置过where 如果设置过就以用户设置为准,没有设置就为空
protected function parseWhere()
{
if (isset($this->options['where'][0])) {
return 'WHERE ' .$this->options['where'][0];
} else {
return '';
}
}
//判断用户设置过group 如果设置过就以用户设置为准,没有设置就为空
protected function parseGroup()
{
if (isset($this->options['where'][0])) {
return 'GROUP BY ' .$this->options['group'][0];
} else {
return '';
}
}
//判断用户设置过having如果设置过就以用户设置为准,没有设置就为空
protected function parseHaving()
{
if (isset($this->options['having'][0])) {
return 'HAVING ' .$this->options['having'][0];
} else {
return '';
}
}
//判断用户设置过order如果设置过就以用户设置为准,没有设置就为空
protected function parseOrder()
{
if (isset($this->options['order'][0])) {
return 'ORDER BY ' .$this->options['order'][0];
} else {
return '';
}
}
//limit可以有以下几种传法
protected function parseLimit()
{
if (isset($this->options['limit'][0])) {
if (is_int($this->options['limit'][0])) {
//用户传进来的是一个整 数,就是查询指定的条数
return 'LIMIT ' . $this->options['limit'][0];
} else if (is_array($this->options['limit'][0])){
//用户传进来的是一个数组,则数组中的第一个元素为$offset,第二个元素为$num
return 'LIMIT ' . join(',',$this->options['limit'][0]);
} else {
//如果户传进来的是一个字符串,则以用户传的为准
return 'LIMIT ' . $this->options['limit'][0];
}
} else {
return '';
}
}
//插入的成员方法
public function insert($data)
{
//SQL语句
$sql = "insert into %TABLE%(%FIELDS%) values(%VALUES%) ";
//替换
$newsql = str_replace(
array(
'%TABLE%',
'%FIELDS%',
'%VALUES%'
),
array(
$this->parseTable(),
$this->parseInsertFieldes($data),
join (',',$this->parseValue($data)),
),
$sql
);
//重新赋值
$this->sql = $newsql;
echo $this->sql;
//调用exec并执行
return $this->exec($newsql,true);
}
//处理插入时候的字段
protected function parseInsertFieldes(&$data)
{
foreach ($data as $key => $value) {
if (!in_array($key,$this->fields)) {
unset($data[$key]);
}
}
return join(',',array_keys($data));
}
//处理插入时候的值
//分为字符串 数组 空的情况处理
protected function parseValue($data)
{
if (is_string($data)) {
$data = '\'' . $data . '\'';
} else if (is_array($data)){
$data = array_map(array($this, 'parseValue'),$data);
} else if (is_null($data)){
$data = 'null';
}
return $data;
}
//
public function exec($sql,$isInsertId = false)
{
$result = mysqli_query($this->link,$sql);
if ($result) {
if ($isInsertId) {
//insertfan返回自动增长的id
return mysqli_insert_id($this->link);
} else {
//update delete 返回受影响的行数
return mysqli_affected_rows($this->link);
}
} else {
return false;
}
}
//更新方法
public function update($data)
{
$sql = "update %TABLE% set %SETS% %WHERE% %ORDER% %LIMIT%";
$newsql = str_replace(
array(
'%TABLE%',
'%SETS%',
'%WHERE%',
'%ORDER%',
'%LIMIT%'
),
array(
$this->parseTable(),
$this->parseSets($data),
$this->parseWhere(),
$this->parseOrder(),
$this->parseLimit(),
),
$sql
);
$this->sql = $newsql;
//echo $newsql;
return $this->exec($newsql);
}
//更新内容设置
protected function parseSets($data)
{
$sets = [];
foreach ($data as $key => $value) {
if (in_array($key,$this->fields)) {
$sets[] = $key . '=' . $this->parseValue($value);
}
}
return join(',',$sets);
}
//删除方法
public function delete()
{
$sql = "delete from %TABLE% %WHERE% %ORDER% %LIMIT%";
$newsql = str_replace(
array(
'%TABLE%',
'%WHERE%',
'%ORDER%',
'%LIMIT%'
),
array(
$this->parseTable(),
$this->parseWhere(),
$this->parseOrder(),
$this->parseLimit(),
),
$sql
);
$this->sql = $newsql;
return $this->exec($newsql);
}
//求总数
public function sum($field = null )
{
if (is_null($field)) {
$field = $this->fields['_pk'];
}
$sql = "select count($field) as sum from %TABLE% %WHERE% ";
$newsql = str_replace(
array(
'%TABLE%',
'%WHERE%',
),
array(
$this->parseTable(),
$this->parseWhere(),
),
$sql
);
$this->sql = $newsql;
$data = $this->query($newsql);
return $data[0]['sum'];
}
//求最大数
public function max($field = null )
{
if (is_null($field)) {
$field = $this->fields['_pk'];
}
$sql = "select max($field) as max from %TABLE% %WHERE% ";
$newsql = str_replace(
array(
'%TABLE%',
'%WHERE%',
),
array(
$this->parseTable(),
$this->parseWhere(),
),
$sql
);
$this->sql = $newsql;
$data = $this->query($newsql);
return $data[0]['max'];
}
//求最小数
public function min($field = null )
{
if (is_null($field)) {
$field = $this->fields['_pk'];
}
$sql = "select min($field) as min from %TABLE% %WHERE% ";
$newsql = str_replace(
array(
'%TABLE%',
'%WHERE%',
),
array(
$this->parseTable(),
$this->parseWhere(),
),
$sql
);
$this->sql = $newsql;
$data = $this->query($newsql);
return $data[0]['min'];
}
//求平均数
public function avg($field = null )
{
if (is_null($field)) {
$field = $this->fields['_pk'];
}
$sql = "select avg($field) as avg from %TABLE% %WHERE% ";
$newsql = str_replace(
array(
'%TABLE%',
'%WHERE%',
),
array(
$this->parseTable(),
$this->parseWhere(),
),
$sql
);
$this->sql = $newsql;
$data = $this->query($newsql);
return $data[0]['avg'];
}
//自动的一个按照字段来查询的智能化查询方法
protected function getBy($field,$value)
{
$sql = "select %FIELDS% from %TABLE% %WHERE%";
$newsql = str_replace(
array(
'%FIELDS%',
'%TABLE%',
'%WHERE%'
),
array(
$this->parseFields(),
$this->parseTable(),
' WHERE '.$field . "='$value'",
),
$sql
);
$this->sql = $newsql;
echo $newsql;
return $this->query($newsql);
}
//__call方法,针对用户请求limit(), order(),group()等将其保存到options中, 判断其方法合法性;
//并且return $this 让其能够连贯操作,
public function __call($func,$args)
{
//合法的
$allow = ['where','table','fields','order','limit','group','having'];
//把传入的统一转化为小写
$func = strtolower($func);
if (in_array($func,$allow)) {
$this->options[$func] = $args;
return $this;
} else if(substr($func,0,5) == 'getby'){
$field = substr($func,5);
if (in_array($field,$this->fields)) {
return $this->getBy($field,$args[0]);
}
} else {
exit ('方法不合法!');
}
}
//析構方法 關閉頁面/對象消費時候調用
public function __destruct()
{
mysqli_close($this->link);
}
}
三、测试(验证)代码:
//包含文件
$config = include 'config.php';
$blog = new UserModel($config);
//测试查询
$data = $blog->fields('uid,uesrname,password')->table('bbs_user')->limit([1,2])->order('uid desc ')->group('username')->select();
var_dump($data);
//插入测试
$_POST['uesrname'] = 'chen';
$_POST['password'] = 123456;
$_POST['creatime'] = 123423;
$_POST['senlin'] = '不存在的字段处理';
echo $blog->insert($_POST);
//更新测试
$_POST['uesrname'] = '1kkkkk12';
$_POST['password'] = 123456;
$_POST['createtime'] = 234567;
$_POST['haiyan'] = '你可长点心眼吧';
echo $blog->where('uid>0')->limit('1')->update($_POST);
//删除测试
echo $blog->where('uid>0 and uid<2')->delete();
//测试求和
echo $blog->sum('uid');
//测试求最大数
echo $blog->max('uid');
//测试求最小数
echo $blog->min();
//测试求平均數
echo $blog->avg();
//测试自动的一个按照字段来查询
$data = $blog->getByPassword('123456');
var_dump($data);