# :-: 一、命名空間
* 命名空間: 解決全局成員的命名沖突問題, 借鑒了文件目錄的基本思想
* 目錄: 同一目錄下不允許重名文件, 但不同目錄下, 允許同名文件存在
* 空間: 同一空間內不允許成員重名, 但不同空間內, 允許同名成員存在
* 命名空間使用 "namespace" 關鍵字聲明
```php
// 如果是相同的名字,php是不運行的
const NAME = '歐陽克';
function sum() {}
class Demo {}
const NAME = '黃蓉';
function sum() {}
class Demo {}
```
>[info] 使用命名空間
```php
namespace red;
class Test {}
namespace green;
class Test {}
namespace blue;
class Test {}
```
>[info] 命名空間,"大括號" 來聲明空間
```php
namespace one
{
class Test {}
}
// 空間: two
namespace two
{
class Test {}
}
// 匿名空間代表: 全局空間, 也是默認的空間,或叫根空間,用 \ 表示
namespace
{
class Test {}
}
```
* 例如: php同時引入兩個文件,文件中都有add方法。
* 例如: 合肥有條北京路, 上海也有條北京路, 但不會有人認為這是同一條路,因為用城市做了區隔
* 所以, 城市,就是路名的命名空間,這樣的例子生活中到處都是,不難理解
* 目前我們只關心 "類" 的命名空間
*****
# :-: 二、類與對象
* 定義: `class`
* 實例化: `new`
```php
namespace admin;
// 關鍵詞: 類, new, 類實例, 對象, 對象檢測
// 類定義
// 類: 是生成對象的代碼模板
class People
{
//...
}
// 對象: 類的實例化, 是類的一個具體實現案例
// 例如: 動物是類, 而小豬, 則是動物類的一個具體的實現案例
// 注意: "實例" 與 "對象" 是同義詞, 大多情況下可互換
$obj1 = new People();
$obj2 = new People();
$obj3 = new People();
// 3個對象都是Demo01類的實例,有不同的#id
var_dump($obj1);
echo '<br>';
var_dump($obj2);
echo '<br>';
var_dump($obj3);
echo '<hr>';
// 檢測對象是否是同一個類的實例
var_dump($obj1 instanceof Demo1);
echo '<br>';
var_dump($obj2 instanceof Demo1);
echo '<br>';
var_dump($obj3 instanceof Demo1);
echo '<hr>';
// 3個對象雖是同一個類的實例,但彼此并不相等,是完全獨立的
var_dump($obj1 == $obj2);
echo '<br>';
var_dump($obj2 === $obj3);
```
*****
# :-: 三、對象屬性
* 類中的屬性,也叫: 成員變量
* 屬性的語法與變量類似,但也是有區別的:
* 在類中聲明屬性變量時,需要通過訪問限定符,設置它的作用域
* 屬性: 初始化必須使用常數,不得使用表達式
* public 是訪問限制符,可視為屬性作用域(可見性)
* public 是指該屬性不論是類內,類外,子類都是可訪問的
* 訪問限定符還有protected,private,目前我們先學習public
```php
namespace admin;
class Demo{
// 為什么叫實例屬性? 因為只能用類的實例, 即對象來訪問它
// 設置了初始值, 并約定在類外部可以訪問
public $product = '手機';
public $price = 2800;
}
// 調用類/函數的代碼叫: 客戶端, 以后我們還會頻繁的使用這個名詞
// 以下代碼其實都是客戶端代碼
// 通過類的實例對象訪問
// 創建類實例對象
$obj = new Demo();
// 輸出當前實例屬性的值
echo '品名: ' .$obj->product .', 價格: ' . $obj->price . '<br>';
echo '<hr>';
// 動態對象屬性:
// 屬性除了可以聲明在類的內外, 在類的外部,也可以動態的添加
$obj->brand = '華為';
echo '品牌: ' . $obj->brand;
// get_class_vars()返回類中public屬性的屬性組成的數組
// 因為使用了命名空間, 完整的類名應該包括了命名空間的, 可以使用::class來獲取完整的類名
$properties = get_class_vars(Demo::class);
echo '<pre>'.print_r($properties,true);
// 注意: 用戶自定義動態屬性不會出現在屬性清單中
```
* 動態屬性: 肯定,必然是對象屬性,只能通過對象添加與訪問
* 動態屬性: 因為是在類外部添加,所以只能是public類型
* 動態屬性: 因為不在類中聲明,不會得到編輯器的提示, 也不會檢查拼寫錯誤
* 所以, 實際開發中, 幾乎用不到動態屬性,大家知道即可, 盡可能不要去使用它
*****
# :-: 四、對象方法
* 對象方法的定義與訪問
* `self`: 當前類
* `$this`: 當前類實例對象的引用
```php
namespace admin;
class Demo{
// 實例屬性
public $product = '手機';
public $price = 2800;
// 實例方法
public function getInfo1(){
// self : 當前類
$obj = new self();
// 輸出實例屬性
return '品名: ' .$obj->product .', 價格: ' . $obj->price . '<br>';
}
// 實例方法
public function getInfo2(){
// 因為該方法必須通過對象調用,所有沒必要在類中實例化
// 直接引用該類的實例化對象即可
// 在類中使用偽變量: "$this" 引用當前類的實例
// $this = new self(); 相當于先執行了這條語句,盡管你不需要這樣做
return '品名: ' .$this->product .', 價格: ' . $this->price . '<br>';
}
}
// 類實例化
$obj = new Demo();
echo $obj->getInfo1();
echo $obj->getInfo2();
// 查看類中定義的對象方法: public 才會顯示出來
$methods = get_class_methods(Demo::class);
echo '<pre>'.print_r($methods,true);
```
*****
# :-: 五、構造方法與析構方法
* 構造方法用來初始化對象成員
* 構造函數是類中的特殊方法,在類實例化時會被自動調用,可用來初始化實例成員
* 析構方法在對象被銷毀的時候, 會被自動調用; 不過, 即使沒有這個方法, 也會自動清理對象的
```php
namespace admin;
class Demo{
// 實例屬性
public $product;
public $price;
// 構造方法
public function __construct($product, $price){
$this->product = $product;
$this->price = $price;
}
// 對象方法
public function getInfo(){
return '品名: ' .$this->product .', 價格: ' . $this->price . '<br>';
}
// 析構方法: 在對象被刪除/清理時自動調用
public function __destruct(){
echo '<h3 style="color:red">對象已被清理</h3>';
}
}
// 實例化
$obj = new Demo4('電腦', 5800);
echo $obj->getInfo();
unset($obj);
// $obj = null;
```
>[info] 實戰: 自動連接數據庫
```php
namespace admin;
class Db{
// 連接對象
public $pdo;
// 希望在實例化時, 自動連接數據庫, 這個需求很常見
public function __construct($dsn, $user, $password){
// 使用PDO方式管理數據庫, 連接成功則返回PDO對象,賦值給對象屬性pdo
$this->pdo = new \PDO($dsn, $user, $password);
}
// 析構方法: 在對象被刪除/清理時自動調用
public function __destruct(){
echo '<h3 style="color:red">連接已斷開</h3>';
}
}
// 實例化
$db = new Db('mysql:host=localhost;dbname=php', 'root', 'root');
if ($db->pdo) {
echo '<h2>連接成功</h2>';
}
// 讀取數據庫測試
$stmt = $db->pdo->prepare('SELECT * FROM `user`');
$stmt->execute();
foreach ($stmt->fetchAll(\PDO::FETCH_ASSOC) as $cate) {
print_r($cate); echo '<br>';
}
```
*****
# :-: 六、類的繼承
* 繼承: `extends`
* 擴展: `__construct()`, `method()`
* 重寫: `function parentMethod(){...}` 重寫主要指方法重寫, 屬性重寫意義不大
>[info] 類的繼承
```php
namespace admin;
class Demo{
// 對象屬性
public $product;
public $price;
// 構造方法
public function __construct($product, $price){
$this->product = $product;
$this->price = $price;
}
// 對象方法
public function getInfo(){
return '品名: ' .$this->product .', 價格: ' . $this->price . '<br>';
}
}
// 子類Sub1, 代碼復用
class Sub1 extends Demo{
// ...
}
// 實例化子類Sub, 盡管子類中無任何成員,但是它可以直接調用父類Demo中的全部成員
$sub1 = new Sub1('手機', 3500);
echo $sub1->getInfo() . '<hr>';
```
>[info] 擴展父類功能
```php
// 子類Sub2, 增加屬性和方法
class Sub2 extends Demo{
public $num; // 數量
// 子類的構造方法
public function __construct($product, $price, $num){
// 調用父類的構造方法,否則還要手工把父類中的屬性初始化語句全部寫一遍
// parent:: 調用被覆寫的父類方法內容
parent::__construct($product, $price);
// 只需要添加子類中的成員初始化代碼
$this->num = $num;
}
// 子類中增加一個新方法: 計算總價
public function total(){
return round($this->price * $this->num, 2);
}
}
// 實例化子類
$sub2 = new Sub2('電腦',3980, 13);
// 調用子類方法, 計算總價
echo $sub2->product . '的總價: ' . $sub2->total() . '<hr>';
```
>[info] 方法重寫
```php
// 為了促銷, 通常會根據總價,給予一定的折扣,刺激消費者購買更多的商品或服務
// 第三個子類, 繼承自Sub2, 而Sub2又繼承自Demo5,這就形成了多層級的繼承關系
class Sub3 extends Sub2{
// 重寫父類Sub2total()方法, 增加計算折扣價功能
public function total(){
// 先獲取未打折時的商品總金額
$total = parent::total();
// 設置折扣率
switch (true) {
case ($total > 20000 && $total < 40000):
$discountRate = 0.88; // 88折
break;
case ($total > 40000 && $total < 60000):
$discountRate = 0.78; // 78折
break;
case ($total >= 60000):
$discountRate = 0.68; // 68折
break;
default: // 小于20000元不打折
$discountRate = 1;
}
// 結果四舍五入,保留2位小數
// 獲取折后價
$discountPrice = round($total*$discountRate, 2);
// 如果折扣率小于1, 表示已打折, 給折扣率描紅顯示
if ($discountRate < 1) {
$discountPrice = $discountPrice.' 元, <span style="color: red"> ('.$discountRate.'折)</span>';
}
// 返回折扣價
return $discountPrice;
}
}
// 實例化子類, 88折
$sub3 = new Sub3('電腦',3980, 13); // 7.8折
$sub3 = new Sub3('電腦',3980, 23); // 7.8折
$sub3 = new Sub3('電腦',3980, 3); // 不打折
echo '折扣價: ' . $sub3->total();
```
*****
# :-: 七、訪問控制
* `public`: 默認, 類內,類外,子類都可見
* `protected`: 類內, 子類可見, 類外不可見
* `private`: 類內可見, 子類, 類外不可見
```php
namespace admin;
class Demo{
// 對象屬性
public $name; // 姓名
protected $position; // 職位
private $salary; // 工資
protected $department; // 部門
// 構造方法
public function __construct($name, $position, $salary, $department){
$this->name = $name;
$this->position = $position;
$this->salary = $salary;
$this->department = $department;
}
// 對于不能通過類實例訪問的屬性,應該設置對外的訪問接口
// 獲取器方法
public function getPosition(){
// 職位: 如果不是培訓部員工, 無權查看
return $this->department === '培訓部' ? $this->position : '無權查看';
}
public function getSalary(){
// 工資: 如果不是財務部員工, 無權查看
return $this->department === '財務部' ? $this->salary : '無權查看';
}
// 設置器方法
public function setSalary($value){
// 如果是設置salary工資,則必須是財務部有權限
return $this->department === '財務部' ? $this->salary = $value : '無權更新';
}
}
// 類外部
$obj = new Demo('歐陽克', '講師', 8888, '培訓部');
//$obj = new Demo('歐陽克, '講師', 8888, '財務部');
echo $obj->name, '<br>'; // public
// protected: 外部不能訪問
//echo $obj1->position;
//private: 外部不能訪問
//echo $obj1->salary;
// 培訓部,有權查看職位,但無權查看和設置工資
// 財務部, 無權查看職位, 但是有權查看和設置工資
echo $obj->getPosition(), '<br>';
echo $obj->getSalary(), '<br>';
echo $obj->setSalary(6666);
echo '<hr>';
```
> 繼承,訪問控制
```php
// 創建子類Sub, 演示權限的繼承與擴展
// 如果在子類中訪問父類中的私有屬性private
class Sub extends Demo6{
public function salary(){
// 在子類中直接訪問父類中的private成員是不允許的
// return $this->salary;
}
}
$obj = new Sub('歐陽克', '講師', 9999, '財務部');
// 在正常的思維中, 父類中的private $salary 是只能在Demo6類中使用, 子類不能訪問
echo $obj->salary(); // 報錯,子類中無法訪問父類中的private成員
// 但是我在父類中創建了一個私有成員的訪問接口: getSalary(), 而它的訪問限制中public,可以被子類繼承
// 所以,通過父類中的私有成員的訪問接口方法, 就可以在子類訪問父類中的私有成員了,包括私有屬性和方法都可以
echo $obj->getSalary();
// 不僅能訪問父類的私有屬性, 我還能通過父類提供的訪問接口設置私有屬性的值
$obj->setSalary(5656);
echo '<br>';
echo $obj->getSalary();
```
- 序言
- 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依賴管理工具