面向对象 (OOP-object Oriented Progarmming)
- 面向对象和面向过程
- 大象装冰箱
- 面向过程
- 1 打开冰箱门
- 2 把大象装进去
- 3 关闭冰箱门
- 面向对象
- 1 建立对象:冰箱,大象.
- 1 冰箱-开门
- 2 大象.进冰箱
- 3 冰箱.关门
- 1 建立对象:冰箱,大象.
- 面向过程好写 面向对象好改;
类 对象
- 类实例化==>对象
- 对象抽象==>类
- 类有属性==>面向过程中的 变量
- 类有方法==>面向过程中的 函数
- 封装
- 把内部逻辑封装起来,外部只有调用的权限,没有修改的权限
- 继承
- 子类可以继承父类的属性(变量)和方法(函数)
金刚鹦鹉(学舌(),毛,飞(),生长())==>鹦鹉类(学舌(),毛,飞(),生长())==>生物(生长());
- 多态
- 调用者不一样,执行逻辑不一样
如何声明一个类
- 语法
[修饰符] class 类名{
[修饰符] [属性]
[修饰符] [方法]
}
- 类的命名规范(大驼峰)
<?php
class Person{
public $name = 'xiaoming';
public $age = 18;
public $sex = 'man';
}
?>
属性中的变量可以初始化,但是初始化的值,必须是常数,可以直接获取值,不需要运算
-
从类实例化对象
$对象名 = new 类名() //"()"可加可不加
调用类的属性和方法 用
->
<?php
//定义一个类
class Person{
public name = null;
public function eat(){
echo "吃肉肉..........";
}
public function drink(){
echo "喝酒..........";
}
}
//把这个类实例化
$people = new Person;
$people->drink(); // 输出 喝酒.........
$people->name = "张三"; //属性赋值
echo $people->name; //属性调用
?>
$this 当前方法或属性的调用者
对象之间的赋值,是按引用传递.
继承
class A extends B{
}
//A 是子类 B 是父类
封装
权限控制符,用来修饰属性和方法
权限控制符 public:公共的 protected:受保护的 private:私人的
- public 都可以访问的到
- Protected 子类和自身可以调用,外部不能调用
- private 私人的,最严格的的权限,只有自己能调用
魔术方法
构造方法__construct()__
实例化对象时自动触发
析构方法__destruct__
对象销毁时自动触发,触发时的三种方法
- 脚本结束
- unset(对象)
- 对象 = null
静态属性 静态方法
static 来定义静态属性和静态方法,不用实例化对象,就可以直接访问,只能用类来访问,使用::
来调用
<?php
class Test{
public static $course = "English";
public static $score;
}
echo Test::$course; //外部调用
<?php
// 内部调用 使用self::属性/方法
class Test{
public static $course = "English";
public static $score = 0;
public static function hello(){
echo self::$score = 100; // 内部调用, 使用self::属性/方法名
}
}
echo Test::hello();
定义常量,使用const关键字来定义一个常量,一般常量名都是大写的,区分大小写 常量不能修改值,只能销毁后重新定义
在类中定义的常量只能通过静态方式来调用
重载
通过魔术方法,动态创建类属性和方法
属性重载
当调用当前环境下未定义
或者不可见
的类属性或类方法时,重载方法会被调用
- 不可访问的属性赋值
__set()
<?php
class Person
{
private $sex = 'male';
public function __set($name, $value)
{
echo $name, ' ', $value;
}
}
$stu = new Person();
$stu->sex = 'female';
- 获取不可访问的属性值,触发
__get()
<?php
class Person
{
private $sex = 'male';
protected $age = 39;
public function __get($name)
{
if ($name == 'age') {
echo "年龄 不是你想看, 想看就能看";
}
}
}
$stu = new Person();
$stu->age;
- 对不可访问属性调用
isset()
或empty()
时,__isset()
会被调用
<?php
class Person
{
private $sex = 'male';
protected $age = 39;
public function __isset($name)
{
echo $name;
}
}
$stu = new Person();
isset($stu->sex);
- 当对不可访问属性调用
unset()
时,__unset()
会被调用
<?php
class Person
{
private $sex = 'male';
protected $age = 39;
public function __unset($name)
{
echo "您正在尝试销毁一个没有权限的属性 $name";
unset(this->$name);
}
}
$stu = new Person();
unset($stu->sex);
方法重载
- 在对象中调用一个不可访问方法时,
__call()
会被调用.
<?php
class Person
{
private $sex = 'male';
protected $age = 39;
public function __call($name, $arguments)
{
var_dump($name); // 方法名字
var_dump($arguments); // 参数数组
}
protected function getSex()
{
echo $this->sex;
}
}
$stu = new Person();
$stu->getSex(1, 2, 3, 4);
- 在静态上下文中调用一个不可访问方法时,
__callStatic()
会被调用
<?php
class Animal
{
private function eat()
{
echo 'eat';
}
public static function __callStatic($name, $arguments)
{
echo '调用不存在的--静态--方法名是:' . $name . '参数是:';
print_r($arguments);
}
}
$animal = new Animal();
Animal::smile('可爱', '大笑', '微笑');
继承 extends
子类继承父类所有的公有的和受保护的属性和方法
<?php
class People
{
public $name = "lisi";
protected $age = 39;
private $salary = 1000;
}
class Person extends People
{
}
$P1 = new Person();
echo $P1->name;
echo $P1->age; // 报错
echo $P1->salary; // 报错
继承关键字extends
,一个类继承另一个类,不能继承多个,可以链式继承
class A extends B; //类A 继承 类B
class C extends A; //类C 继承 类A
重写
重写:继承父类中的方法,子类中定义的与父类中同名的方法
当一个子类重写其父类的方法时,PHP不会调用父类中已被重写的方法,是否调用父类的方法取决于子类
<?php
class Person
{
public function sayHi()
{
echo "hi";
}
}
class Student extends Person
{
public function sayHi()
{
echo 'hello';
}
}
$stu = new Student();
$stu->sayHi();
关键字 parent::
访问父类中被重写的属性和方法,可以再父类原有的代码上追加新的代码
<?php
class Person
{
public function sayHi()
{
echo "hi";
}
}
class Student extends Person
{
public function sayHi()
{
parent::sayHi();
echo " and say Hello";
}
}
$stu = new Student();
$stu->sayHi();
final
如果一个类被声明为final
,则不能被继承.
<?php
final class Person{
public $name = 'lisi';
}
class Student extends Person{
public $sex = 'male';
} // 报错, 不能继承
<?php
// 去掉final, 则没有问题
class Person
{
public $name = 'lisi';
}
class Student extends Person
{
public $sex = 'male';
}
如果父类中的方法被声明为final
,则子类无法重写该方法
<?php
// 继承父类的方法
class Person
{
public $name = 'lisi';
public function getName()
{
echo $this->name;
}
}
class Student extends Person
{
public function getName()
{
parent::getName();
echo "\n";
echo "可以继承父类!";
}
}
$stu = new Student();
$stu->getName();
同样的代码,如果在getName函数前,添加final,则会报错
<?php
class Person
{
public $name = 'lisi';
final public function getName() // 会报错
{
echo $this->name;
}
}
class Student extends Person
{
public function getName()
{
parent::getName();
echo "\n";
echo "可以继承父类!";
}
}
$stu = new Student();
$stu->getName();
多态
- 多态(
Polymorphism
)按字面意思就是'多种状态' - 接口的多种不同实行方式即为多态
- 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
抽象类
- 声明一个抽象类,声明关键字
abstract
- 抽象的方法只是声明了其调用方式(参数),不能定义其具体功能的实现,方法只写名字,不写具体内容
- 抽象类不能被实例化
- 抽象方法只能在抽象类里
- 抽象类可以为空,可以不包含抽象方法
声明一个抽象类
abstract class Person{
abstarct public people(){
}
}
具体类继承并且实现
<?php
abstract class MyAbsClass
{
abstract public function func();
}
class ChildClass extends MyAbsClass
{
// 这样写会报错, 因为没有实现抽象类中定义的方法
}
<?php
abstract class MyAbsClass
{
abstract public function func();
}
class ChildClass extends MyAbsClass
{
public function func()
{
// 即便什么都没有写, 也没有关系...
}
}
如果是抽象类继承,则不用事先抽象方法
<?php
abstract class MyAbsClass
{
abstract public function func();
}
abstract class ChildClass extends MyAbsClass
{
// 什么都没写, 也不会报错...
}
抽象类,必须有抽象方法
abstract class MyAbsClass
{
public function func(); // 会报错, 因为没有abstract关键字
}
同理,含有抽象方法的类,必须是抽象类
class MyAbsClass // 会报错, 因为没有abstract关键字
{
abstract public function func();
}
抽象类,必须有抽象方法,至少有一个即可
<?php
abstract class MyAbsClass
{
public $name = '张三';
public $age;
public function test()
{
echo 'hello';
}
abstract public function func();
}
修饰词关键顺序
- 类的属性和方法必须添加访问修饰符(private、protected以及public)
- abstract以及final必须声明在访问修饰符之前
- abstract和final不能共存
- static必须声明在访问修饰符之后
final public static function
接口
- 使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
- 接口中也可以定义常量。
- 接口实现关键字implements
<?php
interface MyInterface
{
const NUM = 123;
public function func();
public function test();
}
class MyClass implements MyInterface
{
public function func()
{
}
public function test()
{
echo 'hello';
}
}
<?php
interface MyInterface
{
const NUM = 123;
public function func();
public function test()
{
echo "test"; // 会报错, 不能有具体方法
};
}
<?php
interface MyInterface
{
const NUM = 123;
public function func();
public function test();
}
class MyClass implements MyInterface
{
public function func()
{
}
// 报错, 因为没有实现test()
}
- 抽象类实现接口, 可以不用实现其中的方法, 但是抽象类的子类必须实现
<?php
interface MyInterface
{
const NUM = 123;
public function func();
public function test();
}
abstract class MyClass implements MyInterface
{
// 没有实现接口的方法, 也不会报错
}
class Demo extends MyClass
{
public function func()
{
// 必须实现, 否则报错
}
public function test()
{
// 必须实现, 否则报错
}
}
- 接口也可以继承关键字extends, 如果接口B继承了接口A, 而普通类 C实现了接口B, 则A和B所有的方法, C都要实现
<?php
interface A
{
public function aaa();
}
interface B extends A
{
public function bbb();
}
class C implements A
{
public function bbb()
{
//
}
public function aaa()
{
}
}
- 一个类可以实现多个接口, 两个接口中的方法都需要实现
<?php
interface A
{
public function aaa();
}
interface B
{
public function bbb();
}
class C implements A, B
{
public function bbb()
{
// 都得实现, 不然报错
}
public function aaa()
{
// 都得实现, 不然报错
}
}
- 继承和实现可以同时使用
<?php
interface A
{
public function aaa();
}
interface B
{
public function bbb();
}
class C
{
public function bbb()
{
}
public function aaa()
{
}
}
class D extends C implements A, B
{
// 类D继承C, C实现了A和B
}
抽象类和接口的区别
1.抽象类有普通的方法,接口没有
2.抽象类可以有自己的成员属性和方法,接口只能有public 常量。
3.抽象类可有可无构造方法,接口没有构造方法
4.抽象类单继承,接口多重继承
类型运算符
instanceof
用于确定一个PHP变量是否属于某一类class的实例
<?php
class A
{
}
class B
{
}
$a = new A();
var_dump($a instanceof A); // true
var_dump($a instanceof B); // false
instanceof
也可用来确定一个变量是不是继承自某一父类的子类的实例
<?php
class A extends B
{
}
class B
{
}
$a = new A();
var_dump($a instanceof A); // true
var_dump($a instanceof B); // true
instanceof
也可用于确定一个变量是不是实现了某个接口的对象的实例
<?php
class A implements B
{
}
interface B
{
}
$a = new A();
var_dump($a instanceof A); // true
var_dump($a instanceof B); // true
类型约束
- PHP5可以使用类型约束
- 函数的参数可以指定其类型
<?php
class A
{
}
class B
{
}
$a = new A();
$b = new B();
function test(A $n)
{
echo "ok";
}
test($a); // 输出ok
test($b); // 报错, 因为$b是B的实例, 不是A的实例
- 如果一个类或接口指定了类型约束,则其所有的子类或实现也都如此
<?php
class A
{
public function aaa(B $n)
{
}
}
class B
{
}
class C extends B
{
public $a = '123';
}
class D extends A
{
}
$a = new A();
$c = new C();
$a->aaa($c);
自动加载
__autoload()
函数也能自动加载类和接口spl_autoload_register()
函数可以注册任意数量的自动加载器,- 当使用尚未被定义的类(class)和接口(interface)时自动去加载。
- 建议使用
spl_autoload_register()
函数 - 不再建议使用
__autoload()
函数,在以后的版本中它可能被弃用
命名空间的基本使用
- 从广义上来说,命名空间是一种封装事物的方法
- 在很多地方都可以见到这种抽象概念
- 例如,在操作系统中目录用来将相关文件分组,对于目录中的文件夹来说,它就扮演了命名空间的角色
编程中常见的两类问题
- 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突
- 比如引入的文件中,有当前文件已经使用的类/函数/常量名
- 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性
定义命名空间
- 命名空间通过关键字
namespace
来声明。 - 如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间
- 声明单个命名空间namespace MyProject
定义命名空间
-
定义子命名空间namespace MyProject\Sub\Level;
-
可以在同一个文件中定义多个命名空间
-
如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与PHP引入命名空间概念前一样。
-
在名称前加上前缀\表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此
-
__NAMESPACE__
常量 -
常量
__NAMESPACE__
的值是包含当前命名空间名称的字符串 -
在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。
<?php
namespace hello\hello1;
var_dump(__NAMESPACE__); // hello\hello1
namespace hello\hello2;
var_dump(__NAMESPACE__); // hello\hello2
复制代码<?php
var_dump(__NAMESPACE__); // ""
复制代码非限定名称, 完全限定名称, 限定名称(绝对路径, 相对路径)
<?php
namespace A\B;
class MyClass
{
public function __construct()
{
echo '空间A\B 中的类 实例化了' . "\n";
}
}
namespace A;
class MyClass
{
public function __construct()
{
echo '空间A 中的类 实例化了' . "\n";
}
}
$obj = new MyClass();// 非限定名称 就近
$obj = new \A\B\MyClass();// 完全限定名称 绝对路径
$obj = new \A\MyClass();// 完全限定名称 绝对路径
$obj = new B\MyClass();//限定名称 相对路径
复制代码include不会改变当前命名空间, 但是include之后, 可以使用引入文件中的命名空间
C:\Users\Administrator\Desktop\imooc\aaa.php
<?php
namespace aaa;
function demo()
{
echo 'aaa';
}
C:\Users\Administrator\Desktop\imooc\bbb.php
<?php
namespace bbb;
function demo()
{
echo 'bbb';
}
include 'aaa.php';
demo(); // bbb
var_dump(__NAMESPACE__); // bbb
\aaa\demo(); // 可以使用aaa.php的命名空间
动态调用命名空间
动态调用函数
<?php
function demo()
{
echo "demo\n";
}
demo(); // 调用demo
$a = 'demo';
$a(); // 同样可以调用demo
动态实例化对象
<?php
class A
{
public function demo()
{
echo "demo\n";
}
}
$a = new A();
$a->demo();
$b = "A";
$c = new $b;
$c->demo();
//动态调用命名空间
<?php
namespace A\B;
function demo()
{
echo "demo\n";
}
namespace A;
demo(); // 会报错, 因为当前命名空间下, 没有demo()
复制代码<?php
namespace A\B;
function demo()
{
echo "demo\n";
}
namespace A;
\A\B\demo(); // 这就会正常了
<?php
namespace A\B;
function demo()
{
echo "demo\n";
}
namespace A;
$a = '\A\B\demo'; // 效果一样, 因为都是完全限定名称
$a = 'A\B\demo';
$a();
<?php
namespace A\B;
function demo()
{
echo "demo\n";
}
namespace A;
$a = 'B\demo'; // 报错, 不支持相对路径
$a();
异常处理
异常
- PHP错误:是属于php程序自身的问题,一般是由非法的语法,环境问题导致的,使得编译器无法通过检查,甚至无法运行的情况。
- PHP异常:一般是业务逻辑上出现的不合预期、与正常流程不同的状况,不是语法错误。
- 异常处理是一种可扩展、易维护的错误处理统一机制,并提供了一种新的面向对象的错误处理方式,用于在指定异常发生时改变脚本的正常流程。和编写程序的流程控制相似。
异常处理的实现
try{ //所有需要进行异常处理的代码都必须放入这个代码块内
... // 在这里可以使用throw语句抛出一个异常对象
}catch(异常对象参数){ //使用该代码块捕获一个异常,并进行处理
... //在这里做异常处理。也可以再次抛出异常
} [catch(,,){
.. .. ..
}]
工作原理
- 试着去执行try中代码,如果没有问题则跳过catch执行catch之后的代码
- Exception 是系统的类
- 若try中代码有异常,则需要手动抛出一个异常对象给了catch中的参数,try中抛出异常之后的代码不再执行,直接跳到catch中,catch中执行完成以后,再继续执行catch之后的代码
细节
- 在catch中可以提示错误信息,但是最重要的是解决异常,实在解决不了的时候再提示错误
- Catch中也可以再嵌套try…catch
- 每个try至少要有一个与之对应的catch,不能出现单独的catch。另外try和catch 之间也不能有任何的代码出现。
- throw 关键字将触发一次处理机制,是个语言结构不是函数,但必须给它传递一个对象作为值
实例
<?php
try {
$error = 'Always throw this error';
throw new Exception($error);
//创建一个异常对象,通过throw语句抛出
echo 'Never executed';
//从这里开始,try代码块内的代码将不会再被执行
} catch (Exception $e) {
echo 'Caught exception:'.$e->getMessage()."\n";
//输出捕获的异常消息
}
echo 'Hello World'; //程序没有崩溃继续向下执行
系统自带的异常处理类
自定义异常
- 自定义和内置的异常处理类在使用税没有太大的区别,只不过在自定义的异常处理类中,可以调用为具体的异常专门编写的处理方法
捕获多个异常
- 在try代码之后,必须至少给出一个catch代码块,也可以将多个catch代码块与一个try代码块关联使用。那么使用多个catch就可以捕获不同的类所产生的异常。如果有多个catch代码块,传递给每一个catch代码块的对象必须具有不同的类型,这样PHP可以找到需要进入哪一个catch代码块。注意顺序。
MYSQLI
mysqli优势及其简介
- 什么是php的MySQLi扩展
- php的MySQLi扩展又称为MySQL增强扩展。从PHP5.0开始可以使用MySQLi, 是一个面向对象的技术(新加功能都会以对象形式添加)i:表示improve(改进)
- MySQLi扩展相对于MySQL扩展的优势
- MySQLi使用面向对象技术,但也支持过程化的使用方式
- 功能增加了,支持事物,支持预处理语句等一些高级操作
- Mysqli扩展支持mysql数据库发布的新特性,即使再发布新的功能,也能很好支持。
- 效率更高,更稳定,更安全性
开启mysqli扩展
- 使用MySQLi,需要加载MySQLi扩展库。
- 请确定 php.ini 开启MySQLi库扩展:
- 检测MySQLi库扩展是否开启
- Phpinfo()
- 使用 extension_loaded() 函数
bool extension_loaded('mysqli');
- 检测函数是否存在 function_exists('mysqli_connect')
- 得到当前已经开启的扩展:get_loaded_extensions() 返回一个数组包含所有新开启的扩展
MySQLi扩展面向对象数据库的使用
- 1 连接Mysqli数据库服务器
- 有两种连接方式
$mysqli->set_charset("utf8")
设置数据库编码
4 执行SQL语句 执行查询(select)语句
- 错误号和错误信息
$mysqli->errno
得到上一部操作产生的错误信息$mysqli-error
的道上一步操作产生的额错误信息
执行非查询语句
5 处理资源结果集
6-7 释放结果集,关闭数据库连接$result->free_result()
释放结果集$mysqli->close()
关闭连接
mysqli_stmt预处理类(推荐你使用的类)
和mysqli和mysqli_result相比的优点
- mysqli和mysqli_result类完成的功能,都可以使用mysqli_stmt完成
- 效率上:高, 就是如果执行多次相同的语句,只有语句数据不同, 因为将一条语句在服务器端准备好,然后将不同的值传给服务器,再让这条语句执行编译一次,使用多次
- 安全上:SQL注入(? 占位) ,后期传的值不会当成SQL语句
效率高,安全,这是我们使用mysqli_stmt的原因,所以推荐你使用它
mysqli_stmt预处理类的成员方法
mysqli_stmt预处理类成员属性拓展 预处理机制(防止SQL语句恶意注入)
mysqli_stmt处理过程-
获取预处理语句对象
- 方式1:使用mysqli对象中的prepare()方法准备要执行的SQL语句,获得一个mysqli_stmt对象。但要将准备的SQL语句中,各有关参数替换为占位符号,通常使用问号(?)作为占位符号。
$stmt=$mysqli->prepare(“insert into tableName values(?,?,?)”);
- 方式2:mysqli对象中的stmt_init()方法获取一个mysqli_stmt对象。但获取mysqli_stmt对象之后,还要通过该对象中的prepare()方法去准备一个要执行的SQL语句
$stmt->prepare(“insert into tableName values(?,?,?)”);
-
绑定参数
- 在bind_param()方法中,第一个参数是必需的,表示该方法中其后多个可选参数变量的数据类型。每个参数的数据类型必须用相应的字符明确给出,表示绑定变量的数据类型字符
- 类型有i-整型,d-浮点型,s-字符串,b-二进制
$stmt->bind_param(‘类型’,分别对应?的变量名);
-
给绑定的变量赋值
-
执行准备好的sql语句,成功时返回 TRUE , 或者在失败时返回 FALSE 。
$stmt->execte($sql);
-
处理操作的sql语句
$stmt->insert_id; //最后一次插入的id
$stmt->affected_rows; //最后一次操作影响的行数
-
使用预处理语句处理SELECT查询结果
$stmt->bind_result($result);
while($stmt->fetch()){绑定的变量}
//bool mysqli_stmt::fetch(void)
- 释放预处理结果
$stmt->close();
- 关闭mysql
$mysqli->close();
使用预处理语句处理SELECT查询结果
<?php
//获取受影响行数
bool $stmt->store_result();//一次性将结果全部取出
$stmt->num_rows;//结果条数(先运行store_result)
// 处理查询结果方式2
$resObj=$stmt->get_result();//获取结果集
$arr=$resObj->fetch_all(MYSQL_ASSOC);//取出所有记录
// 指针移动到n(先运行store_result)
$stmt->data_seek(n);
$stmt->fetch();
?>
使用mysqli执行多条语句
- bool mysqli::multi_query ( string $sql)
<?php
$sql ="select id,goodsname,price from yhshop_goods;";
$sql .=" select * from yhshop_admin;";
$res=$mysqli->multi_query($sql);
if($res){
do{
if($mysqli_result=$mysqli->store_result()){
$row[]=$mysqli_result->fetch_all(MYSQLI_ASSOC);
}
}while($mysqli->more_results()&&$mysqli->next_result());
print_r($row);
}else{
echo $mysqli->error;
}
?>
使用MYSQLI完成事务处理
-
事务处理 (多个SQL要完成的任务看为是一个事务)一件事(有任何一个环节出错,都整个事务撤消, 如果都成功才去提交)
-
目前只有InnoDB和BDB支持事务
-
默认表都是自动提交的(autocommit)
-
步骤
- 1.关闭自动提交
- 2.set autocommit=0
- 3.开启事务
- 4.start transaction sql执行 commit/rollback
PDO
-
PDO的作用
- PHP可以处理各种数据库系统,访问不同的数据库系统,其使用的PHP扩展函数也是不同的。这样比较麻烦,更重要的是使得数据库间的移植难以实现。
- PDO(php data object)提供了一个数据库访问抽象层,为php访问数据库定义了轻量级的、一致性的接口,无论你使用什么数据库,都可以通过一致的函数执行查询和获取数据,大大简化了数据库的操作,并能够屏蔽不同数据库之间的差异,使用 PDO可以很方便地进行跨数据库程序的开发,以及不同数据库间的移植
- PDO可以支持mysql,oracle,mssql,SQL Server等多种数据库
-
开启PDO 扩展
- 使用pdo,需要加载pdo扩展库。请确定 php.ini 开启MySQLi库扩展:
- extension_dir = "F:/wamp/php-5.4.45/ext"
- extension=php_pdo.dll
- extension=php_pdo_mysql.dll
- 重启apache服务
- 使用 extension_loaded() 函数可以检测MySQLi库扩展是否开启
- bool extension_loaded('pdo_mysql');
- 使用pdo,需要加载pdo扩展库。请确定 php.ini 开启MySQLi库扩展:
-
使用PDO操作数据库
<?php
try {
$dsn = "mysql:host=localhost;dbname=shop";
// 用户名
$user = "root";
// 数据库密码
$pass = "root";
// pdo 对象
$options = array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
PDO::ATTR_DEFAULT_FETCH_MODE => 2
);
$pdo = new PDO($dsn, $user, $pass, $options);
}
catch (PDOException $e){
echo $e->getMessage();
}
- PDO对象的成员方法
- 与PDO连接有关的选项
- 设置使用异常的错误模式
- 设置编码格式
- 设置数据库编码
$pdo->exec('set names utf8');
- 设置数据库编码
- 执行SQL语句
-
处理非查询SQL语句
- 在插入记录时,返回最后插入记录的主键id
$pdo->lastinsertid()
- 在插入记录时,返回最后插入记录的主键id
-
PDOStatement对象
- PDOStatement对象不是通过new关键字实例化出来的,而是通过执行PDO对象中prepare()方法,在数据库服务器中准备好一个预处理的SQL语句后直接返回的。
- 如果通过PDO对象的query()方法返回的PDOStatement 对象只代表是一个结果集对象。而通过prepare()方法产生的PDOStatement对象则为一个查询对象,能定义和执行参数化的SQL命令
-
PDOStatement对象成员方法
- 处理资源结果集
PDO预处理
- 执行预处理方式2
- bindColumn()方法
防止SQL注入
- 方式一:quote()方法防止sql注入
- PDO对象中quote方法返回带引号的字符串,可以过滤来自输入中的特殊字符(用反斜线转移)
<?php
$username = $_POST['username'];
$username=$pdo->quote($username);//自动为字符串加上引号<br>
$sql='select * from uesr where username={$username}'//这里$username就不用加引号了
$stmt=$pdo->query($sql);//PDOStatement对象的方法:rowCount():对于select操作返回的结果集中记录的条数,对于INSERT、UPDATE、DELETE返回受影响的记录的条数
echo $stmt->rowCount();
?>
- 方式二:使用prepare()和execute()预处理sql注入(推荐)
$pdo=new PDO('mysql:host=localhost;dbname=phptest','root','123456');
$sql="INSERT stu(name,classid) VALUES(:username,:classid)";
$stmt=$pdo->prepare($sql); //返回stmt对象
$stmt->bindParam(":username",$username,PDO::PARAM_STR);
$stmt->bindParam(":classid",$class,PDO::PARAM_STR);//将变量$class的引用绑定到查询的名字参数‘:class’中
$username=king;$class='php05';$stmt->execute();
$pdo=new PDO('mysql:host=localhost;dbname=phptest','root','123456');
$sql="INSERT stu(name,classid) VALUES(?,?)";//一个(没有传值的)SQL语句
$stmt=$pdo->prepare($sql);//准备查询语句
$stmt->bindParam(1,$username,PDO::PARAM_STR);
$stmt->bindParam(2,$class,PDO::PARAM_STR);//将变量$class绑定到查询的第二个问号参数中
$username='lily';$class='php03'; //为变量赋值
$stmt->execute(); //执行参数绑定值后的准备语句
PDO事务处理
- 事务
- 事务:就是把很多事情当做一件事情来做,要么就都成功,要么就都失败
- 以保证数据的一致性和完整性
- 将多条sql操作(增删改)作为一个操作单元,要么都成功,要么都失败。
- 被操作的表必须是innoDB类型
- 事务处理
Mysql>set autocommit=0;//关闭自动提交
Mysql>start transaction;//开启事务
Mysql>commit;//提交
Mysql>rollback;//回滚
//1.关闭自动提交
$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT,0);
//2.开启事务:
$pdo->beginTransaction();
//提交一个事务:
$pdo->commit();
//回滚一个事务:
$pdo->rollback();
//检测是否在一个事务内:
inTransaction()
try{
$dsn='mysql:host=localhost;dbname=phptest';
$username='root';$passwd='123456';
$options=array(PDO::ATTR_AUTOCOMMIT=>0);
$pdo=new PDO($dsn, $username, $passwd, $options);
$pdo->beginTransaction();//开启事务
$sql='UPDATE userAccount SET money=money-2000 WHERE username="zs"';
$res1=$pdo->exec($sql);
if($res1==0){throw new PDOException(zs转账失败'); }
$res2=$pdo->exec('UPDATE userAccount SET money=money+2000 WHERE username="king"');
if($res2==0){throw new PDOException('king 接收失败');}
$pdo->commit();//提交事务
}catch(PDOException $e){
$pdo->rollBack(); //回滚事务
echo $e->getMessage();
}
memcache
memcache简介
-
Memcache是一个高性能的分布式的内存对象缓存系统。是个开源的软件,可以通过简单的方法,管理数据库在内存中的存取。简单的说就是缓存数据库查询结果(数据)到内存中,然后从内存中读取,从而大大提高读取速度,减少数据库访问次数,以提高动态web应用的速度,提高可扩展性
-
怎么理解memcache?====> Memcache 是只有一张表的数据库,这张表有两个字段分别是主键key 和value,value就是我们要保存的数据,key就是这个数据的id,用来保证我们查找时候的唯一性
memcache使用场景
- 非持久化存储:对数据存储要求不高,服务停止后,里面的数据就会丢失
- 分布式存储:单台数据的内存容量有限,可以在多个电脑上安装memcache 服务
- Key/Value存储:需要缓存的对象或数据以“key/value”对的形式保存在服务器端
Memcache在WEB中的应用
- MemCache缓存系统最主要的就是为了提高动态网页应用,分担数据库检索的压力。对于网站流量比较大的,可以使用memcache缓解数据库的压力,主要的焦点集中在以下两个方面:
- 使用MemCache作为中间缓存层减少数据库的压力。
- MemCache分布式的应用
memcache运行图
- memcache下载安装
// memcache 属于一种非关系型数据库 mysql 关系型数据库
// memcache 属于nosql的一种 not only sql redis ,mongodb
// 安装memcache 完整过程
// 1.下载memcache windows 安装包 下载地址: http://static.runoob.com/download/memcached-1.4.5-amd64.zip
// 2.安装包解压到任意磁盘下,我的位置 在E:/phpstudy/memcached.exe .dll
// 3. cmd 安装 memcached.exe -d install /uninstall memcached.exe -d start /stop
// 4. 使用客户端管理工具来连接memcache telnet(windows 命令) 127.0.0.1(服务器地址 localhost) 11211 (端口)
// 5. windows 里开启telnet 客户端的命令
// 6. 开启步骤 计算-->控制面板-->程序-->打开/关闭windows功能-->telnet 客户端 勾选开启
// 7.add 键名 标识 有效期(秒数,0表示永不过期) 长度 / add name 0 0 8 xiaoming
- 利用telnet连接到memcache
- telnet 127.0.0.1 //连接
- quit //退出
- 输入stats状态信息
- 数据管理命令
- 格式: <命令> <键> <标记> <有效期> <数据长度> 值
stats items 查看标记
stats cachedump 1 0
PHP操作memcache
-
在php中安装memcache拓展详情点击 blog.csdn.net/ad132126/ar…
-
实例化memcache类
$memcache=new memcache;
-
连接memcache服务器
参数1:主机(必写);
参数2:Memcached服务的端口号,默认11211(可选)
- 关闭服务器连接
$memcache->close()
向memcache服务中添加和重置数据
memcache->add("test1","This is a test",false,0);
$memcache->add("test2",array("one","two"),MEMCACHE_COMPRESSED,60*60*24*30);
$memcache->add("test3",new Test(),MEMCACHE_COMPRESSED,time()+60*60*24*31);
向memcache服务中获取与删除数据
demo memcache在开发中的实际应用- 在项目了最常见的Memcache应用就是缓存从数据库中查询的数据结果,以及保存回话控制信息(session)
- 设计的原则,这要数据库中的记录没有被改变,就不需要重新链接数据库反复执行查询语句,相同的查询结果都应该从缓存服务器中获取
function select($sql,Memcache $memcache){
$key=md5($sql); //md5 Sql命令作为memcache 的唯一标识符
$data=$memcache->get($key);
if(!$data){
try{
$pdo=new PDO("mysql:host=localhost;dbname=php","root","root");
}catch(PDOException $e){
die('连接失败');
}
$stmt=$pdo->prepare($sql);
$stmt->execute();
$data=$stmt->fetchAll(PDO::FETCH_ASSOC);
$memcache->add($key,$data,MEMCACHE_COMPRESSED,0);
}
return $data;
}
$memcache=new Memcache;
$memcache->connect('127.0.0.1',11211);
$data=select("select * from stu",$memcache);
var_dump($data);
![](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/9/16/16d3a6f3a5b8b9ed~tplv-t2oaga2asx-image.image)
- 分布式memcache
- 如果有多台memcache服务器最好使用Memcache::addServer()方法来链接服务器端,不能用Memcache::connect()方法进行链接
- 创建分布式memcache服务器连接池
$memcache = new Memcache;
$memcache->addServer('172.16.1.1', 11211);
$memcache->addServer('172.16.1.2', 11211);
$memcache->addServer('172.16.1.3', 11211);
- memcache实例
//1. 创建对象
$mem = new Memcache();
//2. 添加服务
$mem->addServer("192.168.150.250",11211);
$mem->addServer("192.168.150.138",11211);
$mem->addServer("192.168.112.128",11211);
//3. 放置信息
$mem->add("mystr","hello memcache!",MEMCACHE_COMPRESSED,0);
$mem->add("myarray",array(10,20,30,40),MEMCACHE_COMPRESSED,0);
$mem->add("myob",new Stu(),MEMCACHE_COMPRESSED,0);
//4. 获取信息
echo $mem->get("mystr")."<br/>";
var_dump($mem->get('myarray'));
echo "<br/>";
$mem->get("myob")->getinfo();
高级SESSION
- session的存储方式
- session默认是存在文件里的,文件的读取速度相对来说比较慢,并且文件多的时候会造成文件操作的严重滞后.而且本身session机制不能跨机,而访问量大的系统通常都是多台web服务器进行并发处理,如果每台web服务器都各自独立的处理session,就不可能达到跟踪用户的目的
- 解决方法:自定义Session的存储方式。
- 将session信息使用NFS和SAMBA等共享技术保存到其他服务中
- 使用数据库来保存Session 信息
- 使用memcached 来进行Session 存储.
- 改变session的存储方式
- 在PHP.INI中给我们提供了一个配置项
- session.save_handler = files(保存在文件中)
- session.save_handler = memcache(保存在memcache中)
- session.save_handler = user(用户自定义,结合函数一起使用)
- session_set_save_handler()
- 在PHP.INI中给我们提供了一个配置项
- 自定义处理方式步骤
- 1)php.ini中设置session.Save_handler=user
- 2)了解session6个生命周期
- 3)将这六个部分给php注册上去
- 自定义的方式:要求我们根据session 的生命周期,自定义处理函数否则会报错。需要告诉系统各个时期自定义的函数,就是需要注册这些函数,通过session_set_save_handler()函数,让php自己处理session时,按照这个函数指定的周期来完成。
- 4)Session_start()之前注册这六个部分。
session_set_save_handler()
bool session_set_save_handler ( callable $open ,
callable $close , callable $read , callable $write ,
callable $destroy , callable $gc [, callable $create_sid ] )
-
session_set_save_handler() 设置用户自定义 会话存储函数。 如果想使用 PHP 内置的会话存储机制之外的方式, 可以使用本函数。 例如,可以自定义会话存储函数来将会话数据存储到数据库。这个函数共需要6个回调函数作为必选参数,分别代表了session生命周期中的6个过程,用户通过自定义每个函数,来设置session周期中每个环节的信息处理
-
参数
自定义session存入文件中
使用数据库处理session信息
- 使用数据包处理Session信息,至少包含三个字段(SessionId,修改时间,session 内容信息)
create table session(
sid char(32) not null default '',
update_time int not null default 0,
data text,
primary key(sid)
);
- session自定义存入数据库中