0、准备工作,创建数据表 users
CREATE DATABASE IF NOT EXISTS `test`;
USE `test`;
CREATE TABLE IF NOT EXISTS `users`(
id int unsigned auto_increment,
email varchar(255) not null default '',
password varchar(255) not null default '',
primary key(`id`)
)auto_increment=1,charset=utf8,engine=innodb;
1、数据库连接 http://php.net/manual/zh/pdo.connections.php
PDO::__construct ( string $dsn
[, string $username
[, string $password
[, array $driver_options
]]] )
$driver_options 数组 长连接设置 PDO::ATTR_PERSISTENT=>true
$dsn = 'mysql://host=127.0.0.1;port=3306;dbname=test;charset=utf8'; // dsn
$user = 'root'; // 帐号
$pass = ''; // 密码
$dbh = new PDO($dsn,$user,$pass);
// $dbh = new PDO($dsn,$user,$pass,[PDO::ATTR_PERSISTENT=>1]); // 长连接
var_dump($dbh);
2、执行sql语句 exec() 执行非查询语句的sql(select ...) 返回影响的行数或者false
int PDO::exec ( string $statement
)
// 正常的非查询操作返回影响行数
$sql = 'insert into users(email,password) value(\'qweqwe@asd.com\',\''.md5('dsfsadsafasf').'\')';
$rt = $dbh->exec($sql);
var_dump($rt); // int(1)
若执行的sql不存在语法错误的情况下slq会执行但是影响行数为0
如下代码:
// 执行查询sql语句
$sql = 'select * from users';
// 没有满足wher条件的记录 更新了0行 也就是影响了0行
$sql = 'update users set email=\'fanyilong@163.com\' where id>10000';
$rt = $dbh->exec($sql);
var_dump($rt); // int(0)
如果sql有错误返回false
// user表不存在 sql存在语法错误 返回false
$sql = 'update user set email=\'fanyilong@163.com\' where id>10000';
$rt = $dbh->exec($sql);
var_dump($rt); // bool(false)
所以判断exec是否执行成功要用严格判断 因为exec也会返回 0 $dbh->exec($sql) === false;
3、执行所有的sql PDOStatement query($sql) http://php.net/manual/zh/pdo.query.php
可以执行所有类型的sql 执行成功返回PDOStatement 对象执行 若执行错误返回false
public PDOStatement PDO::query ( string $statement
)
// 返回PDOStatement 插入更新等操作返回的不是false就是执行成功 并返回PDOStatement
$sql = 'select * from users';
$sql = 'insert into user(email,password) value(\'fanyilong_v5@cmd.net\',\''.md5('123456').'\')';
$sql = 'select * from user'; // sql执行错误 表user不存在 返回false
$rt = $dbh->query($sql);
var_dump($rt);
foreach($rt as $key=>$val){
<span style="white-space:pre"> </span>print_r($val);
}
查询sql若执行成功返回 对象 PDOStatement (存储有查询的结果数据) foreach可以直接对返回的对象进行遍历
执行insert update等非查询sql 执行成功返回PDOStatement
执行失败query 会返回false
4、预处理的形式执行sql 这样可防止sql注入
预处理带有占位符的sql字符串
select * from users where id>?
select * from users where id>:id
这里的 '?' ':id' 都是占位符 预处理模式会转义这些参数防止sql注入
public PDOStatement PDO::prepare ( string $statement
[, array $driver_options
= array() ] )
$sql = 'select * from users where id>:id';
$stmt = $dbh->prepare($sql);
var_dump($stmt);
下面的方法是 PDOStatement类的:
绑定参数到占位符
bool PDOStatement::bindValue ( mixed $parameter
, mixed $value
[, int $data_type
= PDO::PARAM_STR ] )
bool PDOStatement::bindParam ( mixed $parameter
, mixed &$variable
[, int $data_type
= PDO::PARAM_STR [, int $length
[, mixed $driver_options
]]] )
设置查询结果的组织形式
参数可以是 PDO::FETCH_* 的常量 PDO常量可以在这里查看 http://php.net/manual/zh/pdo.constants.php
bool PDOStatement::setFetchMode ( int $mode
)
执行预处理函数
bool PDOStatement::execute ([ array $input_parameters
] )
查询执行
获取一条
mixed PDOStatement::fetch ([ int $fetch_style
[, int $cursor_orientation
= PDO::FETCH_ORI_NEXT[, int $cursor_offset
= 0 ]]] )
获取所有条
array PDOStatement::fetchAll ([ int $fetch_style
[, mixed $fetch_argument
[, array $ctor_args
= array() ]]] )
示例代码:
$sql = 'select * from users where id>:id';
$stmt = $dbh->prepare($sql);
// bindPatam参数绑定形式
$id=1;
$stmt->bindParam('id',$id);
// 直接绑定
$stmt->bindValue('id',1);
$stmt->execute(); // 执行预处理sql
// 设置结果集数据形式
$stmt->setFetchMode(PDO::FETCH_ASSOC);
// 查询一条数据
$rt1 = $stmt->fetch();
// 查询全部
$rt2 = $stmt->fetchAll();
var_dump($rt1);
var_dump($rt2);
关于参数绑定:
bindValidate(key,val); 直接指定绑定的参数
a、?作为占位符的情况
$stmt = $dbh->prepare('select * from user where id>? and email!=?');
$stmt->bindValue(1,1);
$stmt->bindValue(2,'fantasy@sina.com');
$stmt->execute();
print_r($stmt->fetchAll());
?占位符在绑定的时候 bindValue第一个参数指定?的序列 这个序列从1开始(而不是从零) bindValue(n,value) 就是将value绑定到第n个?
b、以 :field 作为占位符
$stmt = $dbh->prepare('select * from user where id>:id and email!=:email');
$stmt->bindValue('id',1);
$stmt->bindValue('email','fantasy@sina.com');
$stmt->execute();
print_r($stmt->fetchAll());
bindValue 的第一个参数是 占位符 :field 中的 field bindValue(field,value) 也就是将value绑定到占位符为 :field 的地方
c、? 与 :key 混合的形式作为占位符
$stmt = $dbh->prepare('select * from user where id>? and email!=:email');
$stmt->bindValue(1,1);
$stmt->bindValue('email','fantasy@sina.com');
$stmt->execute();
print_r($stmt->fetchAll());
这种形式会报错 : Invalid parameter number: mixed named and positional parameters
可参照php官网的一个例子 @link http://php.net/manual/en/pdostatement.bindparam.php#98715
bindParam(key,$value) 绑定变量到sql中
第二个参数必须是变量的引用,像bindValue一样传递常量会报错。
php5.3以后 在函数调用传递一用变量不用加 & 符了,只用在函数定义的时候对参数进行引用声明即可
function func(&$arg){......} func('aaa');
使用方法与bindValue类似,
$stmt = $dbh->prepare('select * from user where id>? and email!=?');
$id = 1;
$email = 'fantasy@sina.com';
$stmt->bindParam(1,$id);
$stmt->bindParam(2,$email);
$stmt = $dbh->prepare('select * from user where id>:id and email!=:email');
$id = 1;
$email = 'fantasy@sina.com';
$stmt->bindParam('id',$id);
$stmt->bindParam('email',$email);
execut绑定参数 execut(args_array)
在两种不同的占位符的情况下的绑定形式如下:
?占位符
$stmt = $dbh->prepare('select * from user where id>? and email!=?');
$stmt->execute([1,'fantasy@sina.com']);
print_r($stmt->fetchAll());
:field 占位符
$stmt = $dbh->prepare('select * from user where id>:id and email!=:email');
$stmt->execute(['id'=>1,'email'=>'fantasy@sina.com']);
print_r($stmt->fetchAll());
非常值得注意的一点是 bindParam() 的一个坑就是 这个函数第二个参数是引用,在foreach循环调用的时候会出现一个bug
这个是鸟哥的解释 http://www.laruence.com/2012/10/16/2831.html
当我们这样使用bindParam的时候
$stmt=$dbh->prepare('select * from users where title=:title and name=:name');
$params = [':title'=>'head of artical',':name'=>'fantasy'];
foreach($params as $key=>$val){
$stmt->bindParam($key,$val);
}
这样绑定的结果是 select * from users where title='fantasy' and name='fantasy';
分析原因 bindParam 的第二个参数是引用型变量
分解上面的foreach 相当于:
$val = $params[':id'];
$dbh->bindParam(':id',&$val);
$val = $params[':name'];
$dbh->bindParam(':name',&$val);
同一个变量 $val 分别绑定到了 id 与 name 并且第三行修改了 $val内存中的值
这样 绑定参数的两处值也会因此改变为 第三行修改到的值