本次课程中细致讲解了关于接口与trait的基本语法与使用场景,老师希望大家能深刻理解课堂中讲解的相关内容。
接口继承是重点所在,trait的基本功能是代码复用,请分别用实例展示。
接口继承实例:
<?php
// 接口的使用场景2:多接口继承,一个接口同时继承多个接口
// 接口可以突破php类的继承限制, 允许多继承, 形成了多层级的接口
interface iStudent
{
// 接口常量
const COLLEDGE = 'XX大学';
}
interface iStudent1 extends iStudent
{
// 接口常量
const MAJOR = '网络编程';
}
// 接口实现多继承
interface iStudent2 extends iStudent, iStudent1
{
// 接口方法
public function message();
}
// 实现类
class Student implements iStudent, iStudent1,iStudent2
{
// 必须实现接口中的抽象方法
public function message()
{
return iStudent1::MAJOR . ' 是 ' .iStudent::COLLEDGE.'重点专业之一!' ;
}
}
echo ( new Student)->message();
echo '<hr>';
// 实现类1
class Student1 implements iStudent2
{
// 必须实现接口中的抽象方法
public function message()
{
return iStudent1::MAJOR . ' 目前是 ' .iStudent::COLLEDGE.'重点专业之一!' ;
}
}
echo ( new Student1)->message();
// 接口场景3: 用抽象类来部分实现一个接口
interface iDbBase
{
// 接口方法
// 这里全部采用静态方法, 可省去实例化操作
// 数据库常用的CURD(增删改查)操作
public static function insert($db, $data);
public static function select($db, $options=[]);
public static function update($db,$options);
public static function delete($db, $where);
// 连接数据库
public static function connect($dsn, $username, $password);
}
// 用一个抽象类只实现接口的连接方法: connect()
abstract class aDb implements iDbBase
{
protected static $db = null;
public static function connect($dsn, $username, $password)
{
if (is_null(self::$db)) {
try {
// 连接数据库, 创建pdo对象
self::$db = new \PDO($dsn, $username, $password);
} catch (PDOException $e) {
die($e->getMessage());
}
}
return self::$db;
}
}
// 工作类: 通用查询
class DB1 extends aDb
{
public static function insert($db, $data)
{
// ...
}
public static function select($db, $options=[])
{
$sql = 'SELECT `id`,`name`,`email` FROM `users` LIMIT 5';
return$db->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
}
public static function update($db,$options)
{
}
public static function delete($db, $where)
{
// ...
}
}
// 客户端
$config = [
'type' => $type ?? 'mysql',
'host' => $hsot ?? 'localhost',
'dbname' => $dbname ?? 'phpedu',
'charset' => $charset ?? 'utf8',
'port' => $port ?? '3306',
'username' => $username ?? 'root',
'password' => $password ?? '123456',
];
// 创建PDO数据源
$dsn = sprintf('%s:host=%s;dbname=%s;',$config['type'],$config['host'],$config['dbname']);
// 使用自定义用户密码
$username = $config['username'];
$password = 'root';
// 连接数据库: 实际上调用的是抽象类中的connect()方法完成,返回连接对象$db
$db = DB1::connect($dsn, $username, $password);
// 查询操作
$users = DB1::select($db);
// 遍历结果集
foreach ($users as list('id'=>$id, 'name'=>$name,'email'=>$email)) {
printf('%s => %s : %s <br>', $id, $name, $email);
}
echo '<hr>';
// 接口使用场景4: 接口是实现多态的重要手段
// 1. 数据库操作接口
interface iDb
{
// 构造方法: 用于连接数据库
public function __construct(...$params);
// 1. 新增
public function insert(array $data);
// 2. 查询
public function select(array $options = []);
// 3. 更新
public function update(array $options);
// 4. 删除
public function delete(array $where);
}
/////////////////////////////////////////////////////////
// 2. 使用PDO方式实现iDB接口, 仅以查询select()演示
class DB_PDO implements iDb
{
protected $db = null;
public function __construct(...$params)
{
list($dsn, $username, $password) = $params;
$this->db = new PDO($dsn, $username, $password);
}
// 1. 新增
public function insert(array $data)
{
// ...
}
// 2. 查询
public function select(array $options = [])
{
echo '<h3>PDO:</h3>';
$sql = 'SELECT `id`,`name`,`email` FROM `users` LIMIT 3';
return $this->db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}
// 3. 更新
public function update(array $options)
{
// ...
}
// 4. 删除
public function delete(array $where)
{
// ...
}
}
/////////////////////////////////////////////////////////
// 3. 使用MySQLi方式实现iDB接口,仅以查询select()演示
class DB_MySQLi implements iDb
{
protected $db = null;
public function __construct(...$params)
{
list($host, $username, $password, $dbname, $charset) = $params;
$this->db = new MySQLi($host, $username, $password, $dbname);
$this->db->set_charset($charset);
}
// 1. 新增
public function insert(array $data)
{
// ...
}
// 2. 查询
public function select(array $options = [])
{
echo '<h3>MySQLi:</h3>';
$sql = 'SELECT `id`,`name`,`email` FROM `users` LIMIT 3';
return $this->db->query($sql)->fetch_all(MYSQLI_ASSOC);
}
// 3. 更新
public function update(array $options)
{
// ...
}
// 4. 删除
public function delete(array $where)
{
// ...
}
}
/////////////////////////////////////////////////////////
// 4. 创建数据库通用操作类,用来统一客户端调用方式(静态实现)
class DB
{
// 新增
public static function insert(iDb $db, array $data)
{
return $db->insert($data);
}
// 查询
public static function select(iDb $db, array $options = [])
{
return $db->select($options = []);
}
// 更新
public static function update(iDb $db, array $options)
{
return $db->update($options);
}
// 删除
public static function delete(iDb $db, array $where)
{
return $db->delete($where);
}
}
/////////////////////////////////////////////////////////
// 客户端代码
$config = [
'type' => $type ?? 'mysql',
'host' => $host ?? 'localhost',
'dbname' => $dbname ?? 'phpedu',
'charset' => $charset ?? 'utf8',
'port' => $port ?? '3306',
'username' => $username ?? 'root',
'password' => $password ?? 'root',
];
extract($config);
// 1. PDO实现
$dsn = sprintf('%s:host=%s;dbname=%s;', $type, $host, $dbname);
// 使用自定义密码
$password = 'root';
$db = new DB_PDO($dsn, $username, $password);
$db = new DB_MySQLi($host, $username, $password, $dbname, $charset);
var_dump($db);
// SQL执行操作,以查询为例,无论数据库是什么类型,都无须改动查询代码
// 因为是面向接口编程, DB_PDO, DB_MySQLi都实现了同一接口
// 只要将对象参数的类型限定在接口上就可以实现多态
// 此时, $db 即可是DB_PDO类实例, 也可以是DB_MySQLi类实例, 就看你的心情了
$users = DB::select($db);
// 遍历结果集
foreach ($users as list('id' => $id, 'name' => $name, 'email' => $email)) {
printf('%s => %s : %s <br>', $id, $name, $email);
}
trait实例:
<?php
// trait 功能与语法
// trait: php5.4+, 代码复用
// trait:与抽象类,接口一样不能实例化, 只能嵌入到宿主类中使用
// triat是一个特殊类: 1. 常规, 2. 静态, 3. 抽象, 不能用类常量
trait tDemo
{
// 常规
protected $name = '张嘎子';
public function getName()
{
return $this->name;
}
// 静态
public static $sex = '男';
public static function getSex()
{
return self::$sex;
}
// 抽象
// 抽象静态属性
public static $age;
// 抽象静态方法
abstract public static function getAge();
}
// 客户端
class User
{
// 类中使用trait , 用use 关键
use tDemo;
// 将use tDemo 理解为加载
// require tDemo;
// 常规
// protected $name = '张嘎子';
// public function getName()
// {
// return $this->name;
// }
// // 静态
// public static $sex = '男';
// public static function getSex()
// {
// return self::$sex;
// }
// // 抽象
// // 抽象静态属性
// public static $age;
public static function getAge()
{
return self::$age;
}
}
$user = new User;
User::$age = 16;
echo $user->getName() . ' : ' . User::getSex() . ' ===> ' . User::getAge();
echo '<hr>';
// trait 功能1: 代码复用
trait tDemo1
{
// 格式化打印
public function write()
{
$props =get_class_vars(__CLASS__);
printf('<pre>%s</pre>', print_r($props, true));
}
}
// User1
class User1
{
use tDemo1;
protected $course = '网络编程';
protected $score = 80;
protected $mainpoint = ['类', '接口', 'trait'];
}
(new User1)->write();
// User2
class User2
{
use tDemo1;
protected $course = '网站设计原理';
protected $score = 90;
protected $mainpoint = ['前端', '框架', '数据库'];
}
(new User2)->write();
echo '<hr>';
// trait2: 在继承上下文环境中, 具有优先级, 通过优先的设置, 降低单继承的影响
trait tDemo2
{
public static $name = 'Trait中的属性';
public static function hello()
{
return 'Trait中的方法: ' . __METHOD__;
}
}
// 基类/父类
class Dad
{
// public static $name = '基类中的属性';
public static function hello()
{
return '基类中的方法: ' . __METHOD__;
}
}
// 扩展类/子类
class Son extends Dad
{
use tDemo2;
// trait中的同名方法将父类中同名方法覆盖了, 重写了
// public static $name = '扩展类中的属性';
public static function hello()
{
return '扩展类中的方法: ' . __METHOD__;
}
// 当前类的同名方法又会覆盖掉trait中同名方法
}
// 客户端
echo Son::hello();
// 方法使用的优先级:子类 > trait > 父类
课程学习小结
本次课程老师从浅显易懂的实例出发,细致讲解了接口继承及trait使用的相关内容,通过回看视频及讲义代码,加深了理解,尤其是接口继承及多态的使用场景、trait在宿主类中的使用方法及与父类、子类间调用相应方法的优先级比较等,相关代码基本模仿老师的实例格式进行修改实现,虽然花费了不少时间,但对促使自己多动手实践的习惯养成又进了一步,调试成功后还是感觉挺好的。!