# :-: 一、自動加載
> 普通加載文件
```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依賴管理工具