主要内容:
- 抽象类:部分做到“设计与实现”的分离
- 接口:完全做到“设计与实现”的分离
- 接口之间的继承(连续继承)
- trait:更为灵通的假“类”
- 实战,通过类实现数据增删改查
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. 接口:完全做到“设计与实现”的分离
- 类可以看作是对象的模板。接口有些时候甚至可以看作类的模板。
- 估计意思是接口完全无法实例化。而且只能封装常量和方法 - 因为不允许有属性,而且禁止重写。
- o:接口类似于更为严格的模板,因此也更安全一些。
- o:关于类、接口传参这块不知道有无对应做法。后面可以摸索下。
<?php
// 1. 接口使用场景: 单接口(是否还有双接口,多接口?)
interface iUser
{
// 在接口中所有成员都是抽象的
// 接口成员的访问控制必须是public
// 不允许有属性,但允许有接口常量, 禁止重写
const NATION = 'CHINA';
public function write();
// 接口还可以有构造方法(后面讲)
}
// 2. 接口的实现类
class User implements iUser
{
protected $profession = '最大管理员';
// 接口中的抽象方法,实现类中必须实现
public function write()
{
return '职业:'.$this->profession. ', 国籍: ' . iUser::NATION;
}
}
// 客户端调用
$user = new User();
echo $user->write();
3. 接口之间的继承(连续继承)
<?php
// 接口应用场景2: 接口之间的继承
// php中禁止多重继承: 单继承(一个接口只能继承一个接口,不能继承多接口)
// 接口1
interface iUser
{
const NATION = 'CHINA';
}
// 接口2
interface iUser1 extends iUser
{
const USER_NAME = '机器猫';
}
// 接口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();
<?php
// 接口应用场景3: 用抽象类来实现接口
// ① 定义一个数据库的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 ?? 'phpedu',
// 默认字符编码集
'charset' => $type ?? 'utf8',
// 默认端口号
'port' => $type ?? '3306',
// 默认用户名
'username' => $username ?? 'root',
// 默认用户的密码
'password' => $password ?? 'root'
];
$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);
}
4. trait:更为灵通的假“类”
<?php
// Trait: 特性
// trait: 临时类,类中类, 可以嵌入到宿主类
// trait: trait实现了一个类的横向功能扩展, 继承实现了类的垂直功能扩展
// trait:可以使用类的语句,但不是类。因此不能实例化等。需要用use traitname去调用(有点像php文件间的require)。
trait tDemo
{
// 1.常规成员
protected $name = '机器猫';
public function getName()
{
return $this->name;
}
// 2. 静态成员
protected static $gender = '男';
public static function getGender()
{
return self::$gender;
}
// 3. 抽象成员
public static $age;
abstract static function getAge();
}
// 在一个宿主类/工作类/实现类中使用
class User
{
// 类中使用use 关键字引用trait成员
use tDemo;
// 在宿主类中还必须将trait中的抽象方法实现了
static function getAge()
{
return self::$age;
}
}
// 实例化
$user = new User;
User::$age = 39;
echo $user->getName() . ': ' . $user->getGender(), ': ' .$user->getAge();
5. 实战 - 实现数据库增删该查
<?php
interface iDB{
public static function insert($db, $data);
public static function delete($db, $where);
public static function update($db, $options);
public static function select($db, $options);
}
abstract class aDB implements iDB{
protected static $db = null;
public static function connect($dsn, $username, $password)
{
if (is_null(self::$db)){
self::$db = new PDO($dsn, $username, $password);
}
return self::$db;
}
}
class cDB extends aDB
{
public static function insert($db, $data)
{
$sql = 'INSERT INTO `shao` (`date`, `title`, `label`, `others`) VALUES (?, ?, ?, ?)';
$stmt = $db->prepare($sql);
$stmt->execute($data);
if ($stmt->rowCount() > 0) echo '新增成功 ' . $stmt->rowCount() . ' 条记录,主键id: ' . $db->lastInsertId();
unset($db);
}
public static function delete($db, $where)
{
$sql = 'DELETE FROM `shao` WHERE id = ?';
// 这个地方很有趣,只能传递已经有了的字段的值,不能传递字段名。例如将id也用?代替就不行。
// 不过这块可以通过if条件来进行字段,及中间等号,大于号等的选择。
$stmt = $db->prepare($sql);
$stmt->execute($where);
// if ($stmt->rowCount() > 0) echo '新增成功 ' . $stmt->rowCount() . ' 条记录,主键id: ' . $db->lastInsertId();
// 删除成功后的提示,可以另外考虑。应该是删除前后的rowcount对比之类,或者查询之类的。
unset($db);
}
public static function update($db, $options)
{
$sql = 'UPDATE `shao` SET `date`=?, `title`=?, `label`=?, `others`=? WHERE id = ?';
$stmt = $db->prepare($sql);
$stmt->execute($options);
unset($db);
}
public static function select($db, $options=[])
//这个地方也很奇怪,必须有=[],否则会报错。但其他的几个貌似都不需要。
{
$sql = 'SELECT * FROM `shao` WHERE id > ?';
$stmt = $db->prepare($sql);
$stmt->execute($options);
return $stmt->fetchALL(PDO::FETCH_ASSOC);
var_dump($stmt);
unset($db);
}
}
$config = [
// 类型
'type' => $type ?? 'mysql',
// 默认数据库主机名(IP)
'host' => $host ?? 'localhost',
// 默认数据库名
'dbname' => $type ?? 'liangtest',
// 默认字符编码集
'charset' => $type ?? 'utf8',
// 默认端口号
'port' => $type ?? '3306',
// 默认用户名
'username' => $username ?? 'liang',
// 默认用户的密码
'password' => $password ?? 'xxxxxx'
];
extract($config);
$dsn= sprintf('%s:host=%s;dbname=%s;charset=%s;port=%s',$type,$host,$dbname,$charset,$port);
$db = cDB::connect($dsn, $username, $password);
//$data = ['2020-07-23','多test六下,没准你就成功了','努力,自我训练','NULL'];
//cDB::insert($db,$data);
//$where = ['28'];
//cDB::delete($db,$where);
//$options = ['2020-07-22', 'test八下,肯定会成功','个人,发展','NULL','22'];
//cDB::update($db,$options);
$options = ['25'];
foreach (cDB::select($db,$options) as $item){
print_r($item);
}