PHP高级知识点汇总

1,113 阅读17分钟

面向对象 (OOP-object Oriented Progarmming)

  • 面向对象和面向过程
    • 大象装冰箱
    • 面向过程
      • 1 打开冰箱门
      • 2 把大象装进去
      • 3 关闭冰箱门
    • 面向对象
      • 1 建立对象:冰箱,大象.
        • 1 冰箱-开门
        • 2 大象.进冰箱
        • 3 冰箱.关门
    • 面向过程好写 面向对象好改;

类 对象

  • 类实例化==>对象
  • 对象抽象==>类
  • 类有属性==>面向过程中的 变量
  • 类有方法==>面向过程中的 函数
  • 封装
    • 把内部逻辑封装起来,外部只有调用的权限,没有修改的权限
  • 继承
    • 子类可以继承父类的属性(变量)和方法(函数)
    金刚鹦鹉(学舌(),毛,飞(),生长())==>鹦鹉类(学舌(),毛,飞(),生长())==>生物(生长());
    
  • 多态
    • 调用者不一样,执行逻辑不一样

如何声明一个类

  • 语法
[修饰符] 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数据库服务器
    • 有两种连接方式

判断是否连接成功

3 设置字符集

$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操作数据库

<?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()
  • 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缓解数据库的压力,主要的焦点集中在以下两个方面:
    1. 使用MemCache作为中间缓存层减少数据库的压力。
    2. 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()

  • 自定义处理方式步骤
    • 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自定义存入数据库中

session自定义存入memcache中