1. 抽象类: 部分的分离了”设计与实现”
注意:
- 抽象类不能直接被实例化,是为子类服务的
- 真正被实现的是子类
- 抽象类中的方法必须在子类中实现
<?php
// 抽象类: 部分的分离了"设计与实现"
// 父类: 设计类
abstract class User
{
// 这里的访问控制符,如果这个成员允许在子类中使用,应该声明为protected,否则private
protected $name = '胡八一';
public function write1()
{
return '姓名: ' .$this->name;
}
// 抽象方法: 没有实现,只有声明, 子类中必须实现它
abstract protected function write2();
}
// 子类:实现类, 工作类, 真正干活的是子类
class Work extends User
{
protected $profession = '盗墓的';
public function write2()
{
return parent::write1() . ', 职业: ' . $this->profession;
}
}
// User类只当作父类就不应该允许被实例化
// $user = new User();
// 必须通过它的子类来调用抽象类中的方法
// 客户端代码
$work = new Work();
// echo $work->write1();
echo $work->write2();
2. 接口: 完全分离了”设计与实现”
- 类是对象的模板, 接口是类的模板
- 估计意思是接口完全无法实例化。而且只能封装常量和方法 - 因为不允许有属性,而且禁止重写。
- 接口类似于更为严格的模板,因此也更安全一些。
- 关于类、接口传参这块不知道有无对应做法。后面可以摸索下。
<?php
// 接口: 完全分离了"设计与实现"
// 类是对象的模板, 接口是类的模板
// 1. 接口使用场景: 单接口
interface iUser
{
// 在接口中所有成员都是抽象的
// 接口成员的访问控制必须是public
// 不允许有属性,但允许有接口常量, 禁止重写
const NATION = '18';
public function write();
// 接口还可以有构造方法(后面讲)
}
// 2. 接口的实现类
class User implements iUser
{
protected $profession = 'IT';
// 接口中的抽象方法,实现类中必须实现
public function write()
{
return '职业:'.$this->profession. ', 年龄: ' . iUser::NATION;
}
}
// 客户端调用
$user = new User();
echo $user->write();
3. 接口之间的继承
<?php
// 接口应用场景2: 接口之间的继承
// php中禁止多重继承: 单继承
// 接口1
interface iUser
{
const NATION = '18';
}
// 接口2
interface iUser1 extends iUser
{
const USER_NAME = 'peter';
}
// 接口3
interface iUser2 extends iUser, iUser1
{
public function write();
}
// 实现类
// class User implements iUser, iUser1, iUser2
// iUser2已经继承了iUser, iUser1,所以只需要实现iUser2就可以了
class User implements iUser2
{
// 必须实现接口中的抽象方法
public function write()
{
return '姓名:'.iUser1::USER_NAME. ', 年龄: ' . iUser::NATION;
}
}
// 调用
echo (new User)->write();
4. 通过接口操作数据库
<?php
// 定义一个数据库的CURD接口
interface iDbBase
{
// 新增
public static function insert($db, $data);
// 查询
public static function select($db, $optoins=[]);
// 更新
public static function update($db, $options);
// 删除
public static function delete($db, $where);
}
// 实现类使用抽象类来充当
abstract class aDb implements iDbBase
{
// 使用单例模式连接: 创建类的唯一实例,唯一对象
protected static $db = null;
// 抽象类充当接口实现类时, 不用必须实现接口中的抽象方法
// 当实现类中的方法中有一些公共操作时,可以将这些操作放在中间的抽象类中实现它
public static function connect($dsn, $username, $password)
{
if (is_null(self::$db)) {
// 如果当前连接对象是null,表示未连接数据库
self::$db = new PDO($dsn, $username, $password);
}
return self::$db;
}
}
// 类的真正实现类
class DB extends aDb
{
// 新增
public static function insert($db, $data)
{
}
// 查询
public static function select($db, $optoins=[])
{
return $db->query('SELECT * FROM `users` LIMIT 3')->fetchAll(PDO::FETCH_ASSOC);
}
// 更新
public static function update($db, $options)
{
}
// 删除
public static function delete($db, $where)
{
}
}
// 客户端代码
// 连接参数
$config = [
// 类型
'type' => $type ?? 'mysql',
// 默认数据库主机名(IP)
'host' => $host ?? 'localhost',
// 默认数据库名
'dbname' => $type ?? 'php_edu',
// 默认用户名
'username' => $username ?? 'php.edu',
// 默认用户的密码
'password' => $password ?? '61187118'
// 默认字符编码集
'charset' => $type ?? 'utf8',
// 默认端口号
'port' => $type ?? '3306',
];
$dsn = sprintf('%s:host=%s;dbname=%s;',$config['type'],$config['host'],$config['dbname']);
$username = $config['username'];
$password = $config['password'];
$db =DB::connect($dsn, $username, $password);
// 调用实现类DB中的select()进行查询
foreach (DB::select($db) as $user) {
print_r($user);
}
5. 实战抽象类abstract实现数据库接口iDbBase连接,并增删改查数据
<?php
//1.抽象类实现接口,iDbBase定义一个数据库的CURD接口
interface iDbBase
{
// 新增
public static function insert($db, $data);
// 查询
public static function select($db, $optoins = []);
// 更新
public static function update($db, $optoins);
// 删除
public static function delete($db, $where);
}
//2.实现类改为抽象类 abstract
abstract class aDb implements iDbBase
{
// 使用单例模式连接:创建类的唯一实例,唯一对象
protected static $db = null;
// 实现类中的方法中有公共操作,放在中间的抽象类中实现它
public static function connect($dns, $username, $password)
{
if (is_null(self::$db)) {
// 如果是null 表示未连接
self::$db = new PDO($dns, $username, $password);
}
// 如果连接成功就返回
return self::$db;
}
}
//3.创建一个真正实现类,在这个类进行(增删改查)操作
class DB extends aDb
{
// 新增一条
public static function insert($db, $data)
{
$stmt = $db->prepare('INSERT `users` SET `name`=?, `email`=? , `password`=?;');
$stmt->execute(['Micki', '111@php.cn', sha1('micki123')]);
return "受影响的记录有" . $stmt->rowCount() . "条";
}
// 更新id为8的数据
public static function update($db, $optoins)
{
$stmt = $db->prepare('UPDATE `users` SET `name`=?, `email`= ?, `password`=? WHERE `id` = ?;');
$stmt->execute(['Melinda', '222@php.cn', sha1('melinda123'), 8]);
return "受影响的记录有" . $stmt->rowCount() . "条";
}
// 删除id是6的数据
public static function delete($db, $where)
{
$stmt = $db->prepare('DELETE FROM `users` WHERE `id` = ?;');
$stmt->execute([6]);
return "受影响的记录有" . $stmt->rowCount() . "条";
}
// 查询所有数据
public static function select($db, $optoins = [])
{
return $db->query('SELECT * FROM `users`')->fetchALL(PDO::FETCH_ASSOC);
}
}
//4.连接参数,把config.php这个文档的数据库的参数拿来、配置、调用
$config = [
// 类型
'type' => $type ?? 'mysql',
// 默认数据库主机名(IP)
'host' => $host ?? 'localhost',
// 默认数据库名
'dbname' => $type ?? 'php_edu',
// 默认字符编码集
'charset' => $type ?? 'utf8',
// 默认端口号
'port' => $type ?? '3306',
// 默认用户名
'username' => $username ?? 'php.edu',
// 默认用户的密码
'password' => $password ?? '61187118'
];
// 做配置
$dsn = sprintf('%s:host=%s;dbname=%s;', $config['type'], $config['host'], $config['dbname']);
$username = $config['username'];
$password = $config['password'];
// 调用
$db = DB::connect($dsn, $username, $password);
//5.打印输出
// 1.新增
// echo DB::insert($db, $data);
// 2.修改
// echo DB::update($db, $optoins);
// 3.删除
// echo DB::delete($db, $where);
// 4.查询
// 调用实现类DB中 select()查询,由于是二维数组,要遍历
foreach (DB::select($db) as $user) {
print_r($user);
}
总结
- 感觉抽象类与接口的作用就是为了代码复用