主要内容:
- 序列化与反序列化:serialize(),unserialize()
- sleep(序列化限制)、wakeup(类反序列化时的连带操作) - 序列化类似睡着(哪些东东可以睡着),反序列化类似醒酒(醒酒的时候干点啥)
- 异常类:__toString()异常处理
- 匿名类(寻不到反击的对象:防攻击?老周的娃娃都笑了)
1. 序列化与反序列化:serialize(),unserialize()
<?php
// 序列化,序列化数据的目的是将数据进行传输或保存
echo serialize('peter zhu'), '<br>';
echo serialize([10, false, null]);
echo '<hr>';
class User
{
public $name = '汽车';
public $price ='180000';
public $num = 2;
// 当外部序列化类实例的时候,自动调用它,用来隐藏一些属性
// sleep内部的会包括,其他的会省略掉
// serialize($this)被调用的时候自动执行它
public function __sleep():array
{
return ['name', 'price'];
}
// 外部反序列化这个对象的时候,会被自动调用。例如这个里面对变量重新赋值。
public function __wakeup()
{
// 在唤醒一个对象的时候,可以同步执行一些操作
$this->price = 5000;
}
}
$user = new User();
// 序列化数据的目的是将数据进行传输或保存
file_put_contents('obj.txt', serialize($user));
$str = file_get_contents('obj.txt');
// echo gettype($str);
// 还可以反序列化,并将实例重新得到
// string ===> object
$obj = unserialize($str);
// echo gettype($obj);
echo $obj->name . ': 价格: ' . $obj->price . ', 数量 : ' , $obj->num;
2. sleep(序列化限制)、wakeup(类实例化连带操作)
<?php
// __sleep()和__wakeup()实战
// 自定义数据库连接类
// 功能:
// 1. 类实例化时,自动连接数据库, 一定会生成一个:连接对象
// 2. 将这个连接对象序列化,获取到连接参数
// 3. 反序列化, 自动重新连接数据库
// 连接类
class Connection
{
// 数据库连接参数的属性
private $params = [];
// 连接对象
private $link;
// 构造方法
public function __construct($dsn, $username, $password)
{
// 1. 连接参数的初始化
$this->params['dsn'] = $dsn;
$this->params['username'] = $username;
$this->params['password'] = $password;
// 2. 连接数据库
$this->connect();
}
// 连接数据库
private function connect()
{
$this->link = new PDO(...array_values($this->params));
} // array_values为取出其中的值。
// 将这个连接对象序列化,获取到连接参数
public function __sleep(): array
{
return ['params'];
}
// 反序列化, 自动重新连接数据库
public function __wakeup()
{
$this->connect();
}
// 测试,看是否连接成功,可以取出数
public function select($sql)
{
return $this->link->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}
}
$dsn = 'mysql:host=localhost;dbname=phpedu';
$username = 'root';
$password = 'root';
$db = new Connection($dsn, $username, $password);
// o:构造函数的部分直接传参。对应几个就几个。
$str = serialize($db);
// echo $str;
// print_r($db->select('select * from users limit 3'));
// 3. 反序列化, 自动重新连接数据库(用了类中的__wakeup)
$link = unserialize($str);
// print_r($link);
print_r($db->select('select * from users limit 2'));
3. 异常类:__toString()异常处理
<?php
// toString()
// class User
// {
// public function __toString()
// {
// return 'Hello ';
// }
// }
// 将这个类的实例,当成字符串打印
// $user = new User();
// echo $user;
// __toString()应用场景案例: 异常处理
// php异常处理类: Exception, 这个类除构造方法外, 外部仅有__toString()可访问
// php异常与其它语言(如Java)不同, 大多数异常没有提供预置异常并且不会自动抛出,需要用户手工配置
// Excepction异常类中, 只有属性和__toString()可以在子类中使用
// Exception与try{...}catch (Exception $e) {...}结构配合使用
// - 与错误机制对比, 异常处理机制主动抛出
// - 异常并不一定是发生了错误, 所以异常应用范围更广
// - 使用框架开发,异常与错误机制已经封装好了,简单的配置就可以直接用了
// ## 2. Exception
// ```php
// Exception {
// /* 属性 */
// protected string $message ;
// protected int $code ;
// protected string $file ;
// protected int $line ;
// /* 方法 */
// public __construct ([ string $message = "" [, int $code = 0 [, Throwable $previous = NULL ]]] )
// final public getMessage ( void ) : string
// final public getPrevious ( void ) : Throwable
// final public getCode ( void ) : int
// final public getFile ( void ) : string
// final public getLine ( void ) : int
// final public getTrace ( void ) : array
// final public getTraceAsString ( void ) : string
// public __toString ( void ) : string
// final private __clone ( void ) : void
// }
//
// try {
// $db = new PDO('mysql:host=localhost;dbname=phpedu', 'root', 'root1');
// // 出错后强制且自动的抛出预置的异常信息
// } catch (Exception $exception) {
// // echo $exception->getMessage(), '<br>';
// echo $exception;
// }
// 自定义自己的数据库异常类
class DbException extends EXception
{
public function __toString()
{
return <<< DBE
<table>
<tr>
<td>编号</td>
<td>信息</td>
<td>文件</td>
<td>行号</td>
</tr>
<tr>
<td>$this->code</td>
<td>$this->message</td>
<td>$this->file</td>
<td>$this->line</td>
</tr>
</table>
<style>
table {border-collapse: collapse;border:1px solid black;text-align: center;}
td {border:1px solid black;padding: 5px;}
tr:first-of-type {background-color:#eee;}
tr:last-of-type td {color: coral;}
</style>
DBE;
}
}
try {
$db = new PDO('mysql:host=localhost;dbname=phpedu', 'root', 'root');
// 自定义异常类需要手工抛出
// 这里需要一个判断,如果连接失败应该实例化自定义的异常类并抛出它
throw new DbException('连接失败', 110);
} catch (DbException $dbException) {
echo $dbException;
}
4. 匿名类(寻不到反击的对象:防攻击?)
<?php
// 匿名类
class Demo
{
public function hello($name)
{
return 'Hello '. $name;
}
}
// 1. 传统语法
$demo = new Demo();
echo $demo->hello('Peter Zhu'), '<hr>';
// 2.如果这个类实例(对象)只用一次, 将类的实例化与成员访问二合一
echo (new Demo())->hello('Peter Zhu'), '<hr>';
// 3. 如果这个类,我们也只用一次,将类的声明,类的实例化,类成员访问三合一
// 此时,可以通过匿名类来实现。其实也就是class中的大括号中的内容拿过来。
echo (new class {
public function hello($name)
{
return 'Hello '. $name;
}
})->hello('Peter Zhu'), '<hr>';
5. 匿名类的mysqli、PDO应用
<?php
// 匿名类的应用场景
// 1. 实现接口的部分功能
interface iDb
{
public function __construct(...$params);
}
// 当前这个接口中的数据库连接操作应该支持PDO,mysqli
// Mysqli实现
// 命名类: 有类名称的类
// 匿名类: 没有名称的类
// 函数也有对应的做法。
// 命名函数: 有名称的函数
// function demo(){
// //....
// }
// 匿名函数: 没有名称的函数
// $demo = function (){
// //....
// };
class My_mysqli implements iDb
{
private $db = null;
public function __construct(...$params)
{
$this->db = new mysqli($params[0], $params[1],$params[2],$params[3]);
}
public function select()
{
return $this->db->query('select * from users limit 2')->fetch_all(MYSQLI_ASSOC);
}
}
$mysqli = new My_mysqli('localhost', 'root', 'root', 'phpedu');
// print_r($mysqli->select());
echo '<hr>';
// 使用匿名类改造
$users = (new class ('localhost', 'root', 'root', 'phpedu') implements iDb {
private $db = null;
public function __construct(...$params)
{
$this->db = new mysqli($params[0], $params[1],$params[2],$params[3]);
}
public function select()
{
return $this->db->query('select * from users limit 2')->fetch_all(MYSQLI_ASSOC);
}
})->select();
// print_r($users);
echo '<hr>';
// pdo实现
class My_pdo implements iDb
{
private $db = null;
public function __construct(...$params)
{
$this->db = new PDO($params[0], $params[1],$params[2]);
}
public function select()
{
return $this->db->query('select * from users limit 3')->fetchAll(PDO::FETCH_ASSOC);
}
}
$mypdo = new My_pdo('mysql:host=localhost;dbname=phpedu', 'root', 'root');
print_r($mypdo->select());
// 匿名类改造pdo实现的接口
$users = (new class ('mysql:host=localhost;dbname=phpedu', 'root', 'root') implements iDb {
private $db = null;
public function __construct(...$params)
{
$this->db = new PDO($params[0], $params[1],$params[2]);
}
public function select()
{
return $this->db->query('select * from users limit 3')->fetchAll(PDO::FETCH_ASSOC);
}
})->select();
echo '------------------------------------------<br>';
print_r($users);
6. 实战
- sleep、wakeup
<?php
/*
0728作业
1. 自定义实例演示:__sleep(), wakeup()实战案例
2. 将课堂上的匿名类实战,加上自己理解重写,添加一个新增方法, 更新方法, 删除方法,
完善这个匿名操作类, mysqli, pdo任选一个完成即可
*/
class Human
{
var $name;
var $height;
var $age;
var $birthyear;
public function __construct($n, $h, $a, $b)
{
$this->name = $n;
$this->height = $h;
$this->age = $a;
$this->birthyear = $b;
}
public function __sleep()
{
return ['name', 'height', 'age', 'birthyear'];
}//因为后面要计算,所以birthyear也需要加入
public function __wakeup()
{
$this->age = 2020 - $this->birthyear;
} // wakeup只在反序列化时有效
}
$person = new Human('张三','175cm','',1990);
$str1 = serialize($person);
echo $str1;
echo '<br><hr>';
//var_dump($person);
//echo '<br><hr>';
file_put_contents('person.txt', serialize($person));
$str = file_get_contents('person.txt');
echo gettype($str);
echo '<br><hr>';
$obj = unserialize($str1);
var_dump($obj);
结果如图:
" class="reference-link">
- 用匿名类操作数据库
<?php
/*
0728作业
1. 自定义实例演示:__sleep(), wakeup()实战案例
2. 将课堂上的匿名类实战,加上自己理解重写,添加一个新增方法, 更新方法, 删除方法,
完善这个匿名操作类, mysqli, pdo任选一个完成即可
*/
interface iData
{
public function __construct(...$params);
}
$items = (new class('mysql:host=localhost;dbname=liangtest',
'liang','123456') implements iData {
private $db = null;
public function __construct(...$params)
{
$this->db = new PDO($params[0],$params[1],$params[2]);
}
public function select()
{
return $this->db->query('SELECT * FROM my_list LIMIT 2')
->fetchAll(PDO::FETCH_ASSOC);
}
})->select();
echo '这是select的匿名实现:<br>';
print_r($items);
echo '<hr>';
$items = (new class('mysql:host=localhost;dbname=liangtest',
'liang','123456') implements iData {
private $db = null;
public function __construct(...$params)
{
$this->db = new PDO($params[0],$params[1],$params[2]);
}
public function delete()
{
return $this->db->query('DELETE FROM my_list WHERE ID = 1')->rowCount();
}
})->delete();
echo '这是delete的匿名实现:<br>';
print_r($items);
echo '<hr>';
$items = (new class('mysql:host=localhost;dbname=liangtest',
'liang','123456') implements iData {
private $db = null;
public function __construct(...$params)
{
$this->db = new PDO($params[0],$params[1],$params[2]);
}
public function update()
{
return $this->db->query('UPDATE my_list SET ID = 1 WHERE ID = 2')->rowCount();
}
})->update();
echo '这是update的匿名实现:<br>';
print_r($items);
echo '<hr>';
$items = (new class('mysql:host=localhost;dbname=liangtest',
'liang','123456') implements iData {
private $db = null;
public function __construct(...$params)
{
$this->db = new PDO($params[0],$params[1],$params[2]);
}
public function insert()
{
return $this->db->query("INSERT INTO my_list (id, name, age, phone)
VALUES ('999','小李飞刀','45','12365')")->rowCount();
}
})->insert();
echo '这是insert的匿名实现:<br>';
print_r($items);
echo '<hr>';