# :-: 一、自动加载
> 普通加载文件
```php
include __DIR__ . '/inc/Test1.php';
include __DIR__ . '/inc/Test2.php';
include __DIR__ . '/inc/Test3.php';
// 查看完整的类名称
echo \inc\Test1::class, '<br>'; // inc/Test1
echo \inc\Test1::class, '<br>'; // inc/Test2
echo \inc\Test1::class, '<br>'; // inc/Test3
echo '<hr>';
// 调用导入的类,访问时, 需要带上类的命名空间
echo \inc\Test1::get(), '<br>';
echo \inc\Test2::get(), '<br>';
echo \inc\Test3::get(), '<br>';
echo '<hr>';
```
>[info] Test1.php、Test2.php、Test3.php 文件
```php
<?php
namespace inc;
class Test1{
public static function get(){
return __CLASS__ . ' 类, 加载成功~~';
}
}
```
>[info] 进阶加载
```php
// 如果当前脚本使用了几十上百这样的类, 上面的方式就很不人性
// 使用下面的自动加载机制, 会根据客户端调用的类, 自动进行加载,效率高, 不出错
// 发现的规律:
// 以要加载的类名: inc\Test1为例, 它的命名空间与类所在目录具有对应关系
// 将类名inc\Test1, 替换成类文件: inc/Test1.php, 就可以实现自动加载
$path = str_replace('\\', '/', \inc\Test1::class);
echo $path, '<br>';
// 加上完整的绝对路径与扩展名
echo __DIR__ . '/'.$path . '.php', '<br>';
// 更新$path
$path = __DIR__ . '/'.$path . '.php';
// 加载 inc/Test1.php
require $path;
// 执行成功, 证明这种方式可以实现类文件加载
echo \inc\Test1::get();
```
* `spl_autoload_register(callback)`: 通过回调自动加载外部文件
```php
// php标准函数库中提供了一个自动加载文件的注册函数,可以实现这个功能
// 这个函数,在当前脚本引用一个未加载的文件时, 会自动调用它的回调方法来加载这个文件
// 该函数的参数是一个回调,回调函数的参数就是当前要加载的类文件
spl_autoload_register(function ($className){
$path = str_replace('\\', '/', $className);
$path = __DIR__ . '/'.$path . '.php';
if (file_exists($path)) {
require $path;
}
});
echo \inc\Test1::get(), '<br>';
echo \inc\Test2::get(), '<br>';
echo \inc\Test3::get(), '<br>';
```
--------------------------------------------
# :-: 二、抽象类
* `abstract`: 定义抽象方法/抽象类
* 类中只要有一个抽象方法, 该类就应该声明为抽象类
* 抽象类只能被继承,不能实例化,并且抽象方法必须在子类实现
* 实现抽象方法的子类方法可见性不能低于抽象方法原定义
* 抽象方法是public, 子类方法只能是public
* 抽象方法是protected, 子类方法只能是protected/public
```php
namespace admin;
class Person{
protected $name;
public function __construct($name='欧阳克'){
$this->name = $name;
}
public function getName(){
return $this->name;
}
public function setName($value){
$this->name = $value;
}
}
$person = new Person();
echo '我的姓名: ' . $person->getName() . '<br>';
$person->setName('黄蓉');
echo '我的姓名: ' . $person->getName() . '<br>';
echo '<hr>';
```
>[info] 一个抽象类必须被扩展为一个特定的类,我们才能创建类实例,使用类中功能
```php
abstract class Person{
protected $name;
protected function __construct($name='peter zhu'){
$this->name = $name;
}
// 该方法不需要重写, 可以通过子类对象访问,应该设置为public
public function getName(){
return $this->name;
}
// 修改属性方法,设置为抽象方法,交给子类实现
// 因为类中有了一个抽象方法, 所以这个类Person也必须设置抽象类, 不允许直接实例化
abstract protected function setName($value);
}
// 子类Stu 扩展了父类 Person
class Stu extends Person{
// 注意: 构造方法不会自动继承, 必须手动重写
public function __construct(string $name = 'peter zhu'){
parent::__construct($name);
}
// 子类中必须实现抽象父类中的抽象方法
public function setName($value){
$this->name = $value;
}
}
$stu = new Stu('欧阳克');
echo '白驼山: ' . $stu->getName() . '<br>';
// 调用子类的重写的抽象方法setName(),来设置属性
$stu->setName('黄蓉');
echo '桃花岛: ' . $stu->getName() . '<br>';
```
* 在实际开发过程中, 通常并不会直接使用一个父类/超类,而是在父类中定义一些方法声明
* 并且确信这个方法肯定是会被子类重写的, 父类中没必要实现,只要给一个方法编写规范即可
* 这个规范包括方法的名称, 参数列表等,具体实现就完全交给子类去完成了
* 相当于公司的部门主管, 接受到老板的任务, 只把属于自己的部分做了, 其它部分, 设置一个标准交给下属去完成
* 这个老板就是接口,我们一会会讲到, 这个部门经理,我们用抽象类实现, 而下属就是子类啦,最终干活的就是子类
--------------------------------------------
# :-: 三、接口
* `interface`: 指定某个类必须实现的方法,但不需要定义方法的具体实现过程
* 接口中仅允许出现: 方法与类常量
* 接口的方法可见性必须是: public
* 接口的方法体必须是空的
* 接口是类的代码模板, 可以像类一样有父子继承关系,例如父接口, 子接口
* `implements`: 类实现接口的关键字, 读音: ['ɪmplɪmɛnts,应波罗曼次]
* 如果仅是部分实现接口中的方法, 请用一个抽象类来实现它
```php
namespace admin;
interface iVehicle{
// 驱动方式: 汽车, 新能源
public function setFuel($fuel);
// 用途
public function setPurpose($purpose);
}
// Car 类 实现了接口: iVehicle
class Car implements iVehicle{
public $fuel;
public $purpose;
// 必须实现的接口方法
public function setFuel($fuel){
$this->fuel = $fuel;
}
// 必须实现的接口方法
public function setPurpose($purpose){
$this->purpose = $purpose;
}
// 类中自定义的对象方法
public function getInfo(){
return $this->fuel . $this->purpose . '车 <br>';
}
}
// Auto 类 实现了接口: iVehicle
class Auto implements iVehicle{
public $fuel;
public $purpose;
// 必须实现的接口方法
public function setFuel($fuel){
$this->fuel = $fuel;
}
// 必须实现的接口方法
public function setPurpose($purpose){
$this->purpose = $purpose;
}
// 类中自定义的对象方法
public function getInfo(){
return $this->fuel . $this->purpose . '车 <br>';
}
}
// Car类的实例化
$car = new Car();
$car->setFuel('新能源');
$car->setPurpose('公交');
echo $car->getInfo();
// Auto类的实例化
$car = new Auto();
$car->setFuel('家用');
$car->setPurpose('燃油');
echo $car->getInfo();
```
--------------------------------------------
# :-: 四、接口实战
* 数据库CURD接口与实现
```php
namespace admin;
// 定义一个接口,实现数据库常用操作:增删改查
interface iCurd{
// 增加数据
public function create($data);
// 读取数据
public function read();
// 更新数据
public function update($data, $where);
// 删除数据
public function delete($where);
}
// 创建Db类, 实现iCurd接口,完成基本的数据库操作
class Db implements iCurd{
//数据库的连接对象
protected $pdo = null;
// 数据表名
protected $table;
// 构造方法: 连接数据库,并设置默认数据表名称
public function __construct($dsn, $user, $password, $table='user'){
$this->pdo = new \PDO($dsn, $user, $password);
$this->table = $table;
}
// 读取
public function read($fields='*', $where='', $limit='0, 5'){
// 设置查询条件
$where = empty($where) ? '' : ' WHERE ' . $where;
// 设置显示数量
$limit = ' LIMIT ' . $limit;
// 预处理查询操作
$sql = 'SELECT '.$fields.' FROM '.$this->table.$where.$limit;
$stmt = $this->pdo->prepare($sql);
$stmt->execute();
// 返回二维数组表示的查询结果集
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
// 新增, 参数是数组: 新记录的键值对
public function create($data){
// 字段列表
$fields = ' (name,phone,sex,pwd,status,last_time)';
// 值列表
$values = '(:name,:phone,:sex,:pwd,:status,:last_time)';
// 创建SQL语句
$sql = 'INSERT INTO '.$this->table.$fields.' VALUES '.$values;
// 预处理执行新增操作
$stmt = $this->pdo->prepare($sql);
$stmt->execute($data);
// 返回新增数量, 新增记录的ID组成的数组
return [
'count'=>$stmt->rowCount(),
'id'=>$this->pdo->lastInsertId()
];
}
// 更新, 为了数据安全, 不允许无条件更新
public function update($data, $where){
// 难点在于SET 参数的处理上,利用传入的$data数组,进行拆装
// 获取数组的键名组成的数组
$keyArr = array_keys($data);
$set = '';
// 遍历键名表示的字段列表,拼装预处理需要的sql语句,注意占符符的表示
foreach ($keyArr as $value) {
$set .= $value . ' = :' .$value. ', ';
}
// 去掉最后一个逗号, 注意每个逗号后有一个空格,去除时也要带上这个空格
$set = rtrim($set,', ');
// 预处理执行更新操作
$sql = 'UPDATE '.$this->table.' SET '.$set .' WHERE ' .$where;
$stmt = $this->pdo->prepare($sql);
$stmt->execute($data);
// 返回被更新的记录数量
return $stmt->rowCount();
}
// 删除: 与更新一样, 这也是危险的写操作, 不允许无条件删除
public function delete($where){
// 预处理执行删除操作
$sql = 'DELETE FROM '.$this->table.' WHERE '.$where;
$stmt = $this->pdo->prepare($sql);
$stmt->execute();
return $stmt->rowCount();
}
}
// 客户端的测试代码
// 实例化Db类
$dsn = 'mysql:host=localhost;dbname=ouyangke';
$user = 'root';
$password = 'root';
$db = new Db($dsn, $user, $password);
// 遍历读取
// 全部
foreach ($db->read() as $item) {
print_r($item); echo '<br>';
}
// 设置查询条件
foreach ($db->read('uid, name, phone', 'age > 50') as $item) {
print_r($item); echo '<br>';
}
echo '<hr>';
// 新增数据
$data = [
'phone'=>'13666668888',
'name'=>'郭靖',
'pwd'=>md5(123456),
'age'=>30,
'sex'=>1,
'status'=>1,
'last_time'=>time()
];
$res = $db->create($data);
echo '成功新增'.$res['count'].'条记录,最新记录的主键ID是: '.$res['id'];
// 更新记录
$data = [
'name'=>'抗金英雄郭靖',
'age' => 40
];
$where = 'uid = 11';
echo '成功更新了: ' .$db->update($data, $where). ' 条记录';
// 删除记录
$where = 'uid = 11';
echo '成功更新了: ' .$db->delete($where). ' 条记录';
```
--------------------------------------------
# :-: 五、后期静态绑定
* 后期静态绑定,也叫"延迟静态绑定"
* 这个技术应用在静态继承的上下文环境中,用于动态调用被重写的方法
* 调用被重写的静态方法使用关键字: `static` 加上"范围解析符"`::`
* `::` 范围解析符的使用场景
* 访问类方法与类常量
* 访问被重写的对象或类方法
* static关键字用来调用重写方法的时候,可以动态的绑定当前调用的类
- 序言
- PHP基础
- 认识PHP
- 环境安装
- PHP语法
- 流程控制
- PHP数组
- PHP函数
- PHP类与对象
- PHP命名空间
- PHP7新特性
- PHP方法库
- PHP交互
- 前后端交互
- 项目常规开发流程
- MySQL数据库
- 会话控制
- Ajax分页技术
- 细说函数
- 类与对象
- 对象进阶
- 类与对象进阶
- OOP面向对象
- 设计模式
- 路由与模板引擎
- 异常类
- PHP爬虫
- PHP抓取函数
- PHP匹配函数
- 正则表达式
- PHP字符串函数
- 抓取实战
- PHP接口
- 了解接口
- PHP插件
- PHPSpreadsheet
- ThinkPHP6
- 安装
- 架构
- 数据库
- 数据库操作
- 视图
- 模版
- 模型
- 杂项
- 命令行
- 交互
- 微信小程序
- 介绍
- 配置
- 组件
- 交互
- API
- 其他知识
- 百度小程序
- 介绍
- 配置
- 组件
- 交互
- API
- 其他知识
- Linux
- 服务器上线流程
- 安装svn
- MySQL
- 认识MySQL
- MySQL函数
- 杂项
- composer依赖管理工具