面向對象:OOP(objected oriented programming)程式設計
面向過程是一種程式設計思想
面向對象程式設計的本質是增加資料和功能的操作主體,即對象
面向對象中的所有的資料和功能多是由主體(對象)來調用和操作
面向對象基礎
面向過程和面向對象差別

面向對象關鍵字
- 類:class,定義面向對象主體的最外層結構,用來包裹主體的資料和功能(函數)
- 對象:object,某類事務的具體代表,又稱為執行個體
- 執行個體化:new,類産生對象的過程
- 類成員:member
- 方法:method,本質是在類class結構中建立的函數,稱之為成員方法或者成員函數
- 屬性:property,本質是在類class結構中建立的變量,稱之為成員變量
- 類常量:const,本質是在類class結構中建立的常量
建立對象
<?php
class People{
}
$man=new People();
# 執行個體化類,man就是對象
var_dump($man);
?>
# 輸出
object(People)#1 (0) { }
#1表示:對象編号,與類無關,是整個腳本中對象的序号
(0)表示:成員變量(屬性)個數
{}表示:具體成員變量資訊(鍵值對)
類對象
<?php
class Buyer{
# 常量聲明
const BIG_NAME='BUYER';
# 常量不需要加 $
# 屬性聲明
# $name;
# 錯誤的,類内部屬性必須使用通路修飾限定符
public $name;
public $money=0;
# 方法聲明
function display(){
echo __CLASS__;
# 魔術常量,輸出類名
# 方法内部變量屬于局部變量
}
}
# 執行個體化
$a = new Buyer();
# 屬性操作,增删改查
echo $a->money;
$a->money='20';
$a->sex='male';
unset($a->name);
echo '<br>';
# 方法操作
$a->display();
echo '<br>';
var_dump($a);
?>
# 輸出
0
Buyer
object(Buyer)#1 (2) { ["money"]=> string(2) "20" ["sex"]=> string(4) "male" }
注意:類常量不是由對象來進行通路
通路修飾限定符
在屬性或者方法前的修飾關鍵字,用來控制屬性或者方法的通路位置
- public:公有,類内和類外都可以通路
- protected:受保護,隻允許在相關類内部通路
- private:私有,隻允許在定義類内部通路
屬性必須有通路修飾限定符,方法可以沒有通路修飾限定符,預設就是 public
類内部對象
$this,方法内部内置的一個對象,會自動指向來調用的方法的對象
$this 存在于方法内部(僅限内部使用),是以相當于在類的結構内部
- 可以通路任意通路修飾限定符修飾的成員
- 私有成員都是通過公有方法來實作通路(公有方法可以在類外部通路)
<?php
class Article
{
protected $name = 'a';
private $type = 'art';
public function get_name()
{
var_dump($this);
}
}
$a = new Article();
var_dump($a);
?>
# 輸出
object(Article)#1 (2) { ["name:protected"]=> string(1) "a" ["type:private"]=> string(3) "art" }
$this 代表的是對象,而 $this 所在環境為類内部的方法内部,是以 $this 對象是在類内部通路,是以所有的屬性和方法,不受通路修飾限定符限制
構造方法
- __construct() 是一種系統内置的魔術方法,該方法的特性是在對象執行個體化之後,對象立即自動調用
- 構造方法的目的就是為了初始化資源,包括對象屬性和其他資源
- 一旦構造方法定義好後,且構造方法自帶參數,那麼就隻能使用 new 類名(參數清單) 方式才能正确執行個體化
- 魔術方法也可以通過對象直接調用的方式調用,不過沒有實際用處
<?php
class Article{
public $name='xiaoli';
private $sex="male";
public function __construct($name,$sex)
{
$this->name = $name;
$this->sex = $sex;
}
}
$a = new Article('xiaowang', 'famale');
var_dump($a);
?>
析構方法
- __destruct(),對象在被銷毀時自動調用,釋放資源
- 對象銷毀
- 對象無變量指向(變量指向其他資料)
- 對象被主動銷毀(unset銷毀對象變量)
- 腳本執行結束(自動釋放資源)
- PHP 腳本執行結束會釋放所有資源,是以一般較少用析構方法
<?php
class Article
{
protected $name = 'xiaoli';
private $sex = 'famale';
public function __destruct()
{
// TODO: Implement __destruct() method.
echo __FUNCTION__;
}
}
$a=new Article();
# 銷毀對象
$a=1;
unset($a);
# __destructend
echo 'end';
?>
# 不銷毀對象,php在運作結束也會釋放資源
# end__destruct
對象傳值
定義:将儲存對象的變量指派給另外一個變量
在 PHP 中,對象的傳值是引用傳遞:即一個對象變量指派給另外一個變量,兩個變量指向同一個對象位址,即隻有一個對象
<?php
class Article
{
public $name = 'xiaoli';
public $sex = 'famale';
}
$a=new Article();
$b=$a;
var_dump($a,$b);
echo '<br>';
$a->name="wangxiaohu";
var_dump($a,$b);
echo '<br>';
?>
# 輸出
object(Article)#1 (2) { ["name"]=> string(6) "xiaoli" ["sex"]=> string(6) "famale" } object(Article)#1 (2) { ["name"]=> string(6) "xiaoli" ["sex"]=> string(6) "famale" }
object(Article)#1 (2) { ["name"]=> string(10) "wangxiaohu" ["sex"]=> string(6) "famale" } object(Article)#1 (2) { ["name"]=> string(10) "wangxiaohu" ["sex"]=> string(6) "famale" }
範圍解析操作符(類常量通路)
有兩個冒号組成 “::” ,專門用于類實作類成員操作,可以實作類直接通路類成員
- 範圍解析操作符是用于給類(類名)通路類成員使用的
類名::類成員
- 範圍解析操作符也可以被對象用來當作類使用(不建議)
$對象名::類成員
- 類常量隻能被類通路
<?php
class Article
{
const NAME='ocean';
}
echo Article::NAME;
# 常量是不能通過 Article->NAME 來進行通路的
$a=new Article();
echo $a::NAME;
# 範圍解析操作符相容對象,找到對象所屬類最終進行通路,效率降低,靈活性提高
?>
類常量是固定的,而對象的屬性是不同對象不同的
靜态成員
定義:使用 static 關鍵字修飾的類成員,表示該成員屬于類通路
- 靜态成員
- 靜态屬性
- 靜态方法
- 靜态成員是明确用來給類通路的,而不是對象
- 靜态成員隻是多了一個 static 關鍵字修飾,本身也可以被對象通路
- 靜态成員同樣可以使用不同的通路修飾限定符限定,效果一緻
<?php
class Article
{
public static $name = 'hlm';
public static $type = 'art';
public static function getName()
{
return self::$name;
}
}
# 靜态屬性
$a = new Article();
echo Article::$name;
# 靜态方法
echo Article::getName();
?>
self關鍵字
- 在類的内部(方法裡面)使用,代替類名的寫法
- self 如同 $this 代表内部對象一樣,能夠在方法内部代替目前類名
- 能夠保障使用者友善修改類名字
- self 關鍵字是代替類名,是以需要配合範圍解析操作符 ::
<?php
class Article
{
public static function getInstance1()
{
return new self();
}
public static function getInstance2()
{
return new Article();
}
}
$a = Article::getInstance1();
$b = Article::getInstance2();
var_dump($a,$b);
?>
# 輸出
object(Article)#1 (0) { } object(Article)#2 (0) { }
類加載
類的通路必須保證類在記憶體中已經存在,是以需要再用類之前将類所在的 PHP 檔案加載到記憶體中
- 類的加載分為兩種
- 手動加載:在需要使用類之間通過 include 将包含類的檔案引入到記憶體
- 自動加載:提前定義好類結構和位置,寫好引入類檔案代碼,在系統需要類而記憶體不存在的時候想辦法讓寫好的加載類的代碼執行(自動加載是自動運作寫好的加載類的代碼)
- 自動加載兩種方式
- 魔術函數 __autoload:系統自動調用,需要傳入類名,在函數内部實作類的手動加載(PHP7及之後不建議使用此方法)
function __autoload($classname){
# 找到對應的檔案路徑和命名規範,手動加載
}
- 自定義函數:自己定義類的加載實作,然後通過 spl_autoload_register 注冊到自動加載機制(可注冊多個自動加載)
# 自定義類加載函數
function 自定義函數($classname){
# 找到對應的檔案和命名規範,手動加載
}
#注冊自動加載
sql_autoload_register('自定義函數名字')
自動加載要求在聲明類的時候有良好的規範
- 類名與檔案名一緻:類名.php 或者 類名.class.php
- 類檔案分類放好
例:手動加載
Article.php
<?php
class Article{
public function getName(){
return __METHOD__;
}
}
mian.php
<?php
# include 'Article.php';
# 直接加載比較消耗資源,而且如果類已經在記憶體中存在,直接include會報錯,建議判斷後再加載
if(!class_exists('Article')){
include 'Article.php';
}
$a=new Article();
var_dump($a->getName());
# output
string(16) "Article::getName"
自動加載
- __autoload(不建議使用)
一個系統中,可能類檔案會放到不同的路徑下,是以一個完整的自動加載函數,應該要進行檔案判定功能
<?php
function __autoload($classname){
# 形參代指 類名
#組織檔案路徑,假設目前路徑下,有兩個檔案夾下都有類c和類m
$c_file = 'c/' . $classname . '.php';
if (file_exists($c_file)) {
include_once($c_file);
return true;
}
//if 語句如果隻有一行不需要加 {}
//include_once 隻加載一次
$m_file = 'm/' . $classname . '.php';
if (file_exists($m_file)) {
include_once($m_file);
return true;
}
}
$a=new Article();
$b=new Article();
- spl_autoload_register
<?php
function autoload01($classname){
if(!class_exists($classname)){
$file_name=$classname.'.php';
if(file_exists($file_name)) include_once $file_name;
}
}
spl_autoload_register('autoload01');
$a=new Article();
對象克隆
通過已有的對象複制一個新的同樣的對象,但兩者之間并非同一個對象
面向對象進階
面向對象三大特性
封裝、繼承、多态
類的封裝
類的繼承
inherit,子類合法擁有父類的某些權限
- 繼承必須滿足繼承關系:即存在合理的包含關系
- 繼承的本質是子類通過繼承可以直接使用父類已經存在的資料和資料操作
- PHP 使用 extends 關鍵字表示繼承
子類也稱派生類
父類也稱基類
# 父類
class Human{}
# 子類繼承
class Man extends Human{}
類的多态
多态性是指相同的操作或函數、過程可作用于多種類型的對象上并獲得不同的結果
- 需要發生類的繼承,同時出現方法的重寫(override),即子類擁有與父類同名的方法
- 在執行個體化對象的時候讓父類對象指向子類對象(強制類型,PHP不支援,PHP 弱類型很靈活)
- 結果:父類對象表現的子類對象的特點
—PHP繼承—
<?php
class Human{
public function show(){
echo __METHOD__;
}
}
class Man extends Human{}
$m=new Man;
$m->show();
有限繼承
子類在繼承父類的成員時,并非繼承所有内容,而是繼承并使用父類部分内容
- PHP 中繼承的本質是對象繼承
- PHP 中繼承的内容:父類所有公有成員、受保護成員和私有屬性,私有方法不能繼承
- 受保護(protected)成員專于繼承,可以在父類或者子類内部通路
- 私有成員的通路隻能在所屬類中設定公有或者受保護方法實作通路
- 構造方法和析構方法可以被子類繼承,
重寫 Override
override,子類中定義了與父類重名的成員
parent 關鍵字
一種明确通路父類成員的表達方式
方法被重寫後,通路調用的是子類方法,如果想要通路父類方法,可以通過在子類方法中使用 parent 來強制通路父類方法
parent 不能用于通路父類的屬性(靜态屬性可以)
PHP 繼承特點
- PHP 隻能單繼承,隻有一個父類(若繼承多個類,可以使用鍊式繼承)
- PHP 繼承中,隻有私有方法不能繼承
- PHP 允許繼承父類中的構造方法和析構方法
靜态延遲綁定
最終類 Final
使用 final 關鍵字修飾類名,表示此類不可以被繼承
final 關鍵字還能修飾方法,表示方法不能被重寫(通常此時類不會使用 final 關鍵字)
抽象類 Abstract
使用 abstract 關鍵字修飾的類,表示該類隻能被繼承,不能被執行個體化
abstract 關鍵字可以修飾方法,表示方法為抽象方法,抽象方法沒有方法體(沒有{})
抽象方法存在的類必須為抽象類
繼承抽象類的類要麼為抽象類,要麼實作抽象類裡所有的抽象方法
trait 代碼複用
适用于,不同類之間有公共代碼,但是類彼此關系不存在繼承關系,此時可以将公共代碼存儲到 trait 中
trait 内部可以擁有一個類能擁有的成員屬性(包括靜态),成員方法(包括靜态和抽象方法),但不能有類常量
trait 用來代碼複用,不能被執行個體化,不能被繼承
trait 同名
一個類中可能需要引入多個 trait ,而不同 trait 中可能出現同名
接口
Interface,專門用來規範一些共性類必須實作的方法
- 接口不是類,但是與類有類似的結構
- 接口不能執行個體化,類可以實作接口
interface 接口名字{}
class 類名 implements 接口名字{}
接口成員
接口成員隻能有兩類
- 接口常量:const
- 共有的接口方法(普通方法和靜态方法)
PHP 重載
overload,指在一個類中可以出現多個同名方法,彼此之間的參數個數和類型不一樣
用來容錯
屬性重載
當對象通路不存在的或者權限不夠的屬性的時候,自動觸發魔術方法讓代碼不出錯
屬性重載魔術方法
- __get(屬性名):通路不存在或者權限不夠的屬性時觸發
- __set(屬性名,屬性值):設定不存在或者權限不夠的屬性時觸發
- __isset(屬性名):判定不存在或者權限不夠的屬性是觸發
- __unset(屬性名):删除不存在或者權限不夠的屬性時觸發
- __tostring(): 當作字元串
方法重載
對象或者類通路不存在或者權限不夠的方法,自動觸發的魔術方法讓代碼不出錯
- __cal(方法名,方法參數清單):調用不存在或者權限不夠的方法時觸發
- __callStatic(方法名,方法參數清單):調用不存在或者權限不夠的靜态方法時觸發
對象周遊
将對象中的所有屬性以鍵值對的形式取出并進行通路
- 對象是一種複合資料類型,對象中真正儲存的内容是屬性
- 對象的屬性本質也是一種鍵值對關系:名字 = 值
- 對象周遊就是利用 foreach 對對象中的屬性進行取出解析
- 對象周遊遵循通路修飾限定符的限定:即類外隻能周遊所有共有屬性
foreach(對象變量 as [屬性名變量 =>] 屬性值變量){
#屬性名變量代表取出的每個屬性的名字
#屬性值變量代表取出的每個屬性的值
}
Iterator 疊代器
生成器
yield 關鍵字
設計模式
design pattern,是軟體開發人員在軟體開發過程中問題的解決方法
單例模式
singleton,是一種類的設計隻會最多産生一個對象的設計思想
保證資源唯一性
工廠模式
。。。。。。
命名空間
namespace,指人為的将記憶體進行分隔,讓不同記憶體區域的同名結構共存,進而解決在大型項目能出現重名結構問題
基礎文法:
namespace 關鍵字定義空間
命名規則
字母、數字、下劃線,不能以數字開頭
命名空間必須寫在所有代碼之前,定義了一個,之後可以定義多個
子空間
subspace,即在已有空間之上,再在内部進行空間劃分
子空間直接通過 namespace+路徑符号 \ 實作
非限定名稱
直接通路元素本身,代表目前所屬空間(目前目錄)
限定名稱
使用空間名+原名,代表通路目前空間子空間(目前目錄子目錄)
完全限定名稱
從根目錄(全局空間)開始通路,使用 \ 作為全局空間開始符号(根目錄)
全局空間元素通路:使用完全限定名稱通路
命名空間引入
開發人員在軟體開發過程中問題的解決方法
單例模式
singleton,是一種類的設計隻會最多産生一個對象的設計思想[外鍊圖檔轉存中…(img-4deDvbKo-1615809714847)]
保證資源唯一性
工廠模式
。。。。。。
命名空間
namespace,指人為的将記憶體進行分隔,讓不同記憶體區域的同名結構共存,進而解決在大型項目能出現重名結構問題
[外鍊圖檔轉存中…(img-DJfIyxfl-1615809714849)]
基礎文法:
namespace 關鍵字定義空間
命名規則
字母、數字、下劃線,不能以數字開頭
命名空間必須寫在所有代碼之前,定義了一個,之後可以定義多個
[外鍊圖檔轉存中…(img-43eaN2pU-1615809714850)]
子空間
subspace,即在已有空間之上,再在内部進行空間劃分
子空間直接通過 namespace+路徑符号 \ 實作
非限定名稱
直接通路元素本身,代表目前所屬空間(目前目錄)
限定名稱
使用空間名+原名,代表通路目前空間子空間(目前目錄子目錄)
完全限定名稱
從根目錄(全局空間)開始通路,使用 \ 作為全局空間開始符号(根目錄)
全局空間元素通路:使用完全限定名稱通路
[外鍊圖檔轉存中…(img-wR0MBGDz-1615809714851)]
命名空間引入