- 仿ThinkPHP3.2.3的模型用法进行开发,支持其大部分语法
- 使用prepare+execute对SQL操作进行预处理,参数绑定并执行
- 额外封装了ThinkPHP常用的方法:dump函数,M函数,I函数
- 增加了ajaxReturn函数,不过仅支持返回json格式数据
- 更新dump方法,使用thinkphp原封的dump方法
- 增加get_client_ip函数(TP原封照搬)
- field方法支持获取全部字段和字段过滤
- 优化和解决了一两个小bug
- 修复BUG
- 解决使用count()等统计函数时使用fetchSql(true)出现问题的BUG
- 修复表达式查询和多条件查询情况下无限加反引号的Bug
- 增加 TO DO list (其实是BUG清单,先挖好坑)
- 使用类静态变量
static $configs
数组存数据库配置信息 - 使用类静态变量
static $links
数组存数据库连接,相同数据库配置的共享一个 link - 使用上面两种思路,可以通过配置使用不同数据库,同时实现了事务跨模型生效
- 表达式查询增加REGEXP(SQL正则表达式查询)
- 完善对SQL执行出错的错误处理机制(增加了
showError()
成员函数用于打印SQL错误信息)
- 增加对InnoDB存储引擎的共享锁和排他锁的支持
注:可结合ThinkPHP3.2.3的文档参考使用。
配置文件初始化:
<?php
require_once "config.php";
require_once "PDO_MySQL.class.php";
$link = M("users");
参数初始化:
<?php
require_once "PDO_MySQL.class.php";
$dbConfig = array(
'hostname' => '127.0.0.1', # 可选
'username'=>'root', # 可选
'password'=>'pwd', # 如无,程序会使用配置文件声明的数据库密码
'database'=>'db_name', # 必选
);
# 此处的1为配置代号,支持字符串代号,之后可直接使用配置代号切换数据表
$link = M("users", 1, $dbConfig);
推荐使用配置文件的方法,支持的配置信息:
'hostname' => '127.0.0.1', # 可选,服务器地址,默认127.0.0.1
'username' => 'root', # 可选,数据库用户名,默认root
'password' => 'pwd', # 必选,数据库密码
'database' => 'db_name', # 必选,数据库名
'hostport' => '3306', # 可选,端口号,默认3306
'dbms' => 'mysql', # 可选,数据库类型,默认mysql
'pconnect' => false, # 可选,是否开启长连接,默认false
'charset' => 'utf8', # 可选,数据库编码格式
'DB_DEBUG' => true, # 可选,是否开启DEBUG模式,请在系统上线后关闭DEBUG模式
'MYSQL_LOG' => '/mysql.log' # 可选,定义mysql的log文件路径,请先确保有读权限
其中,要定义MYSQL_LOG
,请先开启mysql的通用查询日志(general_log),开启后才能使用getLastLog()函数,而且这会消耗mysql很大的性能,这一项仅仅为了debug。
只有general_log才是记录所有的操作日志,不过会耗费数据库5%-10%的性能,所以一般没什么特别需要,大多数情况是不开的。
开启MySQL通用查询日志
//此方法重启后失效,想永久生效需修改配置文件。
//linux上mysql的配置文件路径示例:/etc/mysql/mysql.conf.d/mysqld.cnf
mysql> set global general_log=1;
mysql> set global general_log_file=/path/to/mysql.log
使用字符串条件直接查询和操作,例如:
$User = M("User"); // 实例化User对象
$User->where('type=1 AND status=1')->select();
最后生成的SQL语句是
SELECT * FROM think_user WHERE type=1 AND status=1
使用字符串条件的时候,建议配合预处理机制,确保更加安全,例如:
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
或者使用:
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
如果 $id
变量来自用户提交或者URL地址的话,如果传入的是非数字类型,则会强制格式化为数字格式后进行查询操作。
字符串预处理格式类型支持指定数字、字符串等,具体可以参考vsprintf方法的参数说明。
数组条件的where用法是ThinkPHP推荐的用法。
支持普通查询
$User = M("User"); // 实例化User对象
$map['name'] = 'thinkphp';
$map['status'] = 1;
// 把查询条件传入查询方法
$User->where($map)->select();
最后生成的SQL语句是
SELECT * FROM think_user WHERE `name`='thinkphp' AND status=1
支持表达式查询
$map['字段1'] = array('表达式','查询条件1');
$map['字段2'] = array('表达式','查询条件2');
$Model->where($map)->select();
支持多次调用。
除了数据表前缀,支持ThinkPHP支持的所有table用法。 建议:在CURD链式调用放于首位。
支持ThinkPHP支持的所有alias用法。
用于查询
$Model->field('id,title,content')->select();
可以给某个字段设置别名,例如:
$Model->field('id,nickname as name')->select();
使用SQL函数
$Model->field('id,SUM(score)')->select();
使用数组参数
$Model->field(array('id','title','content'))->select();
数组方式的定义可以为某些字段定义别名,例如:
$Model->field(array('id','nickname'=>'name'))->select();
对于一些更复杂的字段要求,数组的优势则更加明显,例如:
$Model->field(array('id','concat(name,"-",id)'=>'truename','LEFT(title,7)'=>'sub_title'))->select();
执行的SQL相当于:
SELECT id,concat(name,"-",id) as truename,LEFT(title,7) as sub_title FROM table
支持获取所有字段和过滤字段(详见ThinkPHP3.2.3文档)。
用法与ThinkPHP相同
用法与ThinkPHP相同
只支持两个数字参数的写法:
page(2,10) //表示单页量为10,取第二页,即取出符合条件的第11-20条数据
用法与ThinkPHP相同
用法与ThinkPHP相同
(跟ThinkPHP有较大区别) 只传一个字符串,默认INNER JOIN
M('t1')->join('t2 on t1.id=t2.id')->select();
//相当于select * from t1 INNER JOIN t2 on t1.id=t2.id
传数组 (前两个元素必须是字符串,第二个元素须是"INNER","LEFT","RIGHT","FULL"之一)
M('t1')->join(array('t2 on t1.id=t2.id','LEFT'))->select();
//相当于select * from t1 LEFT JOIN t2 on t1.id=t2.id
支持多次调用。
注:MySQL其实不支持FULL JOIN,建议用 left join + union(可去除重复数据)+ right join 作为替代方案。
用法与ThinkPHP相同
加行锁(共享锁或排他锁),仅支持 InnoDB 存储引擎,仅支持 SELECT 语句,且须在事务块中才能生效 有一个参数,传入字符串 "S" 或 "X",分别代表共享锁和排他锁
$Model->where("id = 1")->lock("X")->select();
执行的SQL相当于
SELECT * FROM table WHERE id = 1 FOR UPDATE
以下操作失败都返回false
读取数据(仅一条)
$data = $User->where('status=1 AND name="thinkphp"')->find();
查询成功返回一维数组,如果无数据返回NULL
读取数据集
$list = $User->where('status=1')->order('create_time')->limit(10)->select();
查询成功返回二维数组,如果无数据返回NULL
传入数组
$User = M("User"); // 实例化User对象
$data['name'] = 'ThinkPHP';
$data['email'] = 'ThinkPHP@gmail.com';
$User->add($data);
插入成功返回插入数据的自增ID(如果无自增ID将返回0)
批量写入(须传入二维数组)
$dataList[] = array('name'=>'thinkphp','email'=>'thinkphp@gamil.com');
$dataList[] = array('name'=>'onethink','email'=>'onethink@gamil.com');
$User->addAll($dataList);
插入成功返回其中第一条插入数据的ID(如果数据表无ID将返回0) 注:如果插入的数据都指定了自增ID,将返回最后一条数据的自增ID
返回值都是影响的记录数(如果更新前的数据和更新后的没有变化,则返回0)
$User = M("User"); // 实例化User对象
// 要修改的数据对象属性赋值
$data['name'] = 'ThinkPHP';
$data['email'] = 'ThinkPHP@gmail.com';
$User->where('id=5')->save($data); // 根据条件更新记录
为了保证数据库的安全,避免出错更新整个数据表,如果没有任何更新条件,数据对象本身也不包含主键字段的话,save方法不会更新任何数据库的记录。 除非使用下面的方式:
$User = M("User"); // 实例化User对象
// 要修改的数据对象属性赋值
$data['id'] = 5;
$data['name'] = 'ThinkPHP';
$data['email'] = 'ThinkPHP@gmail.com';
$User->save($data); // 根据条件保存修改的数据
如果id是数据表的主键的话,系统自动会把主键的值作为更新条件来更新其他字段的值
如果只是更新个别字段的值,可以使用setField 方法:
$User = M("User"); // 实例化User对象
// 更改用户的name值
$User->where('id=5')->setField('name','ThinkPHP');
setField方法支持同时更新多个字段,只需要传入数组即可(这将与save相同)
$User = M("User"); // 实例化User对象
// 更改用户的name和email的值
$data = array('name'=>'ThinkPHP','email'=>'ThinkPHP@gmail.com');
$User->where('id=5')->setField($data);
而对于统计字段(通常指的是数字类型)的更新,还提供了setInc 和setDec 方法。
$User = M("User"); // 实例化User对象
$User->where('id=5')->setInc('score',3); // 用户的积分加3
$User->where('id=5')->setInc('score'); // 用户的积分加1
$User->where('id=5')->setDec('score',5); // 用户的积分减5
$User->where('id=5')->setDec('score'); // 用户的积分减1
不支持延迟更新。
返回是删除的记录数。
不支持传入主键删除数据(与ThinkPHP有区别)
普通用法:
$User->where('status=0')->delete(); // 删除所有状态为0的用户数据
高级用法,delete与join的结合使用:
$User=M('t1');
$User->join('t2 on t2.id = t1.id')->delete('t1');
//DELETE t1 FROM `t1` INNER JOIN t2 on t2.id = t1.id
//表示删除t1表中id与t2的id相同的数据
//delete方法中的参数用于指定删除哪个表中符合条件的数据
与ThinkPHP最大的不同在于使用了"_tosingle""_tomulti"关键词:
"_tosingle"=>true:进行单条件对应查询,示例:
$map['status&title'] =array('1','thinkphp','_tomulti'=>true);
即status=1 AND title='thinkphp'
"_tomulti"=>true:单字段进行多条件查询,示例:$map['name'] = array('ThinkPHP',array('like','%a%'),'or','_tomulti'=>true);
即name='ThinkPHP' OR name LIKE '%a%'
其中"_tomulti"关键词主要是为了与表达式查询做区分。
举个例子:
$map['name'] = array('ThinkPHP','is null')
和$map['name'] = array('exp','is null')
后者本来是表达式查询,但是还可以被辨别为name='exp' AND name='is null'
; 所以干脆给前者加个"_tomulti"=>true
表示非表达式查询,解析为name='ThinkPHP' AND name='is null'
。 后者没有"_tomulti"关键词,解析为name is null
。
支持字符串查询和数组查询,懒得支持对象查询。 以及推荐使用数组查询,因为where查询直接传字符串不做任何检查(不安全所以不支持)
增加了REGEXP(SQL正则表达式查询):
# WHERE `name` REGEXP '^Fran'
$where['name'] = array('REGEXP', '^Fran'); # 可匹配到name为Frankie的数据
# WHERE `name` REGEXP '\d' OR `name` REGEXP '\w'
$where['name'] = array('REGEXP', array('\d', '\w'), 'OR');
其他用法与ThinkPHP相同
与ThinkPHP语法的不同处:
"不同字段不同的查询条件"处不是指定'_multi'=>true
,而是'_tosingle'=>true
比如:$map['status&title'] =array('1','thinkphp','_tosingle'=>true);
=>status=1 AND title='thinkphp'
如果不指定:$map['status&title'] =array('1','thinkphp');
=>(status=1 AND status='thinkphp') AND (title=1 AND title='thinkphp')
文档原文:
区间查询的条件可以支持普通查询的所有表达式,也就是说类似LIKE、GT和EXP这样的表达式都可以支 持。另外区间查询还可以支持更多的条件,只要是针对一个字段的条件都可以写到一起,例如:
$map['name'] = array(array('like','%a%'), array('like','%b%'), array('like','%c%'), 'ThinkPHP','or');
在这里需要加'_tomulti'=>true,用于与表达式查询做区分。
$map['name'] = array(array('like','%a%'), array('like','%b%'), array('like','%c%'), 'ThinkPHP','or','_tomulti'=>true);
最后的查询条件是:
( name LIKE '%a%') OR ( name LIKE '%b%') OR ( name LIKE '%c%') OR ( name = 'ThinkPHP')
用法与ThinkPHP相同
用法与ThinkPHP相同
用法与ThinkPHP相同
不支持动态查询(感觉没什么必要)
用法与ThinkPHP相同
仅对支持事务的数据库驱动起作用。
- 开启事务/startTrans
- 检查是否在一个事务内/inTrans
- 事务回滚/rollback
- 事务提交/commit
使用示例:
$link = M("test");
dump($link->inTrans());//输出false
$link->startTrans();
dump($link->inTrans());//输出true
$link->where('id=4')->save(array('status'=>array('exp','status+100')));
$link->rollback();//事务回滚,事务内的更新无效
dump($link->inTrans());//输出false
$link->where('id=5')->save(array('status'=>array('exp','status+100')));//处于事务外,更新立即生效
用于初始化对一个数据表的连接。
//连接users数据表,如无table方法切换数据表,默认对此表进行操作。
$link = M("users");
暂时只支持get和post(需要再说) 使用htmlspecialchars()对数据进行预处理
高仿 tp的dump方法。
Ajax方式返回数据到客户端 暂时只支持返回json格式数据
获取客户端IP地址
getLastSql()
和_sql()
等效,用于打印最后一条执行的SQL语句(由系统封装)
getLastLog()
则是读取MySQL通用查询日志记录的最后一条SQL语句
其中,当且仅当DEBUG模式开启,以上方法才会输出详细信息。注意,使用getLastLog()
须开启MySQL的通用查询日志以及指定MySQL通用日志目录(见开启MySQL通用查询日志)。
当SQL语句执行出错时可调用showError()
打印详细的错误信息;
当然,也可以通过类成员变量SQLerror
(关联数组,有如下的key)自行取错误信息:
errno:error number
sqlstate:SQLSTATE value
msg:error message
sql:发生错误的SQL语句
其中,当且仅当DEBUG模式开启,以上方法才会输出详细信息。
PHP的html解码/解码函数
事务暂时不支持跨模型操作(2017.12.05完成)- field之字段过滤目前仅支持单表查询