1. 程式人生 > 實用技巧 >PHP面向物件 基礎語法 構造方法 析構方法 繼承 多型

PHP面向物件 基礎語法 構造方法 析構方法 繼承 多型

面向物件介紹

  • 概述

    • 面向物件是一個程式設計思想。程式設計思想有面向過程和麵向物件
      • 面向過程:程式設計思路集中的是過程上
      • 面向物件:程式設計思路集中在參與的物件
  • 好處

    • 多人合作方便
    • 減少程式碼冗餘,靈活性高
    • 程式碼的可重用性發揮到極致
    • 可擴充套件性強
  • 名詞

    • OOP:面向物件程式設計(Object Oriented Programming,面向物件程式設計)
    • OOA: 面向物件分析(Object-Oriented Analysis,OOA)
    • OOD: 面向物件設計(Object-Oriented Design,OOD)

類和物件

  • 概念

    • 物件是具體存在的事物,物件是由屬性(變數)和方法(函式)組成的
    • 類是具有相同屬性和行為的一組物件的集合
    • 一個類可以建立多個物件
  • 理解

    • 物件是由屬性和方法組成的
    • 類是所有物件的相同屬性和方法的集合
    • 在開發的時候先寫類,通過類建立物件,通過物件呼叫方法和屬性
    • 一個類可以建立多個物件

在PHP中實現類和物件

建立類

  • 語法
class 類名{
	//屬性
	//方法
	//常量
}
  • 概念
    • 類是由屬性、方法、常量組成的
    • 也可以說類成員有:屬性、方法、常量

類名的命名規則

  • 規則
    • 以字母、下劃線開頭,後面跟的是字母、數字、下劃線
    • 不能用PHP關鍵字做類名
    • 類名不區分大小寫(變數名區分,關鍵字、類名不區分大小寫)
    • 類名用帕斯卡命名法(大駝峰 單詞的首字母大寫)
<?php
class Student {
    //屬性
	//方法
	//常量
}
?>

物件例項化

  • 通過new關鍵字來例項化物件。
    • 小括號可以省略
<?php
//定義類
class Student {
	//屬性
	//方法
	//常量
}
//例項化物件
$stu1=new Student();
$stu2=new Student;		
var_dump($stu1,$stu2);	
?>

物件的比較

  • 概述
    • 相等:結構和儲存的值一樣就相等
    • 全等:指向同一個物件才是全等
    • 物件的傳遞是地址傳遞
<?php
//定義類
class Student {
	
}
//例項化物件
$stu1=new Student();
$stu2=new Student;
$stu3=$stu2; //物件傳遞的是地址	

var_dump($stu1==$stu2);		//bool(true) ,比較物件的結構
echo '<br>';
var_dump($stu1===$stu2);	//bool(false) $stu1和$stu2是否是同一個物件
echo '<br>';
var_dump($stu2===$stu3);	//bool(true) $stu2和$stu3是同一個物件
?>

PHP面向物件語法結構

屬性

  • 屬性
    • 屬性本質就是變數
    • 屬性前面的public不能省略
    • 通過 -> 呼叫物件的成員
    • 物件名 -> 屬性名
    • 物件名 -> 方法名()
<?php
//定義類
class Student {
	public $name;				//屬性
	public $add='地址不詳';		//屬性
}
//例項化物件
$stu=new Student();
//print_r($stu);	//Student Object ( [name] => [add] => 地址不詳 ) 
//操作屬性
//1、給屬性賦值
$stu->name='tom';
$stu->add='北京';

//2、獲取屬性的值
echo '姓名:'.$stu->name,'<br>';	//姓名:tom
echo '地址:'.$stu->add,'<br>';		//地址:北京

//3、新增屬性
$stu->age=20;
print_r($stu);	//Student Object ( [name] => tom [add] => 北京 [age] => 20 ) 
echo '<br>';
//4、刪除屬性
unset($stu->add);
print_r($stu);	//Student Object ( [name] => tom [age] => 20 ) 
?>

方法

  • 方法
    • 方法的本質就是函式
    • 方法前面public是可以省略的,如果省略,預設就是public的
<?php
class Student {
	//定義方法
	public function show() {
		echo '這是show方法<br>';
	}
	//public可以省略,如果省略,預設就是public
	function test() {
		echo '這是test方法<br>';
	}
}
$stu=new Student;
$stu->show();	//呼叫方法
$stu->test();
?>

訪問修飾符

  • 用來控制成員的訪問許可權

    • public(公有的) 在類的內部和外部都能訪問
    • private(私有的) 只能在類的內部訪問
    • protected(受保護的) 在整個繼承鏈上訪問
  • 作用

    • 保證資料的合法性
    • 一般來說,屬性都用私有的,通過公有的方法對私有的屬性進行賦值和取值
    • this 表示呼叫當前方法的物件
<?php
class Student {
	private $name;	//私有屬性
	private $sex;	  //私有屬性
	//通過公有的方法對私有的屬性進行賦值
	public function setInfo($name,$sex) {
		if($sex!='男' && $sex!='女'){
			echo '性別必須是男或女';
			exit;
		}
		$this->name= $name;   
		$this->sex= $sex;
	}
	//顯示資訊
	public function getInfo() {
		echo '姓名:'.$this->name,'<br>';
		echo '性別:'.$this->sex,'<br>';
	}
}
//例項化
$stu= new Student;
$stu->setInfo('tom','男');
$stu->getInfo();
echo '<hr>';
$stu2= new Student;
$stu2->setInfo('berry','女');
$stu2->getInfo();
?>

類和物件在記憶體中的分佈

  • 說明
    • 物件的本質是一個複雜的變數
    • 類的本質是一個自定義的複雜資料型別
    • 棧區:執行速度快,體積小,儲存基本型別
    • 堆區:執行速度稍慢,體積大,儲存複雜型別
    • 例項化的過程就是分配記憶體空間的過程
    • 物件儲存在堆區,將堆區的地址儲存到棧區

封裝

  • 說明
    • 封裝就是有選擇性的提供資料
    • 通過訪問修飾符來實現封裝

構造方法

  • 語法
    • 構造方法也叫建構函式,當例項化物件的時候自動執行
    • 建構函式可以帶引數,但不能有return
function __construct(){
}
# 注意:前面是兩個下劃線
  • 例題
    • 在其他語言裡,與類名同名的函式是建構函式,在PHP中不允許這種寫法
<?php
class Student {
	public function __construct() {
		echo '這是構造方法<br>';
	}
}
new Student();	//這是構造方法
new Student();	//這是構造方法
?>
<?php
class Student {
	//和類名同名的方法是構造方法,PHP中不建議使用
	public function Student() {
		echo '這是構造方法<br>';
	}
}
new Student();	//這是構造方法
new Student();	//這是構造方法
?>
  • 建構函式作用:初始化成員變數
<?php
class Student {
	private $name;
	private $sex;
	//建構函式初始化成員變數
	public function __construct($name,$sex) {
		$this->name=$name;
		$this->sex=$sex;
	}
	//顯示資訊
	public function show() {
		echo "姓名:{$this->name}<br>";
		echo "性別:{$this->sex}<br>";
	}
}
//例項化
$stu= new Student('tom','男');
$stu->show();
?>

析構方法

  • 語法
    • 當物件銷燬的時候自動呼叫
    • 解構函式不可以帶引數
function __destruct(){

}
<?php
class Student {
	private $name;
	//構造方法
	public function __construct($name) {
		$this->name= $name;
		echo "{$name}出生了<br>";
	}
	//析構方法
	public function __destruct() {
		echo "{$this->name}銷燬了<br>";
	}
}
//測試
$stu1=new Student('tom');
$stu2=new Student('berry');
$stu3=new Student('ketty');
echo '<hr>';
?>

計算機記憶體管理

  • 計算機記憶體管理方式

    • 先進先出,先進後出
    • 先進先出的記憶體管理方式一般用在業務邏輯中,比如秒殺、購票等等
    • 先進後出是計算機的預設記憶體管理方式
  • 思考題:先進後出(堆疊)

<?php
class Student {
	private $name;
	//構造方法
	public function __construct($name) {
		$this->name= $name;
		echo "{$name}出生了<br>";
	}
	//析構方法
	public function __destruct() {
		echo "{$this->name}銷燬了<br>";
	}
}
//測試
$stu1= new Student('tom');
$stu2= new Student('berry');
$stu3= new Student('ketty');
echo '<hr>';
?>
  • 思考題:先進先出(佇列)
<?php
class Student {
	private $name;
	//構造方法
	public function __construct($name) {
		$this->name= $name;
		echo "{$name}出生了<br>";
	}
	//析構方法
	public function __destruct() {
		echo "{$this->name}銷燬了<br>";
	}
}
//測試
new Student('tom');
new Student('berry');
new Student('ketty');
echo '<hr>';
?>
  • 思考題:???
<?php
class Student {
	private $name;
	//構造方法
	public function __construct($name) {
		$this->name= $name;
		echo "{$name}出生了<br>";
	}
	//析構方法
	public function __destruct() {
		echo "{$this->name}銷燬了<br>";
	}
}
//測試
$stu= new Student('tom');
$stu= new Student('berry');
$stu= new Student('ketty');
echo '<hr>';
?>

繼承

  • 介紹

    • 繼承使得程式碼具有層次結構
    • 子類繼承了父類的屬性和方法,實現了程式碼的可重用性
    • 使用extends關鍵字實現繼承
    • 父類和子類是相對的
  • 語法

class 子類 extends 父類 {

}
  • 執行過程
    • 第一步:在Student類中查詢show(),如果找到就呼叫,找不到就到父類中查詢
    • 第二步:在Person類中查詢show()
<?php
class Person {
	public function show() {
		echo "嘿,人類!<br>";
	}
}
class Student extends Person{

} 
$stu= new Student();
$stu->show();
?>

子類中呼叫父類成員

  • 方法
    • 通過例項化父類呼叫父類的成員
    • 通過$this關鍵字呼叫父類的成員
<?php
class Person {
	public function show() {
		echo "嘿,人類!<br>";
	}
}
class Student extends Person{
  public function test1(){
    $person= new Person();
    $person->show();
  }
  public function test2(){
    $this->show();
  }
} 

$stu1= new Student();
$stu1->test1();
echo '<br>';
$stu2= new Student();
$stu2->test2();
?>

protected

  • protected
    • 受保護的,在整個繼承鏈上使用
<?php
class A {
  //在整個繼承鏈上訪問
	protected $num= 10;	
}
class B extends A {	
	public function getNum() {
		echo $this->num;
	}
}
//整個繼承鏈上有A和B
$obj= new B();    
$obj->getNum();	
?>
<?php
class A {
  public function getNum() {
		echo $this->num;
	}
}
class B extends A {	
	//在整個繼承鏈上訪問
	protected $num= 10;	
}
//整個繼承鏈上有A和B
$obj= new B();    
$obj->getNum();	
?>
<?php
class A {
  public function getNum() {
		echo $this->num;
	}
}
class B extends A {	
	//在整個繼承鏈上訪問
	protected $num= 10;	
}
//整個繼承鏈上只有A
$obj= new A();    
$obj->getNum();	
?>

繼承中的建構函式

  • 規則

    • 如果子類有建構函式就呼叫子類的,如果子類沒有就呼叫父類的建構函式
    • 子類的建構函式呼叫後,預設不再呼叫父類的建構函式
  • 語法

    • 通過類名呼叫父類的建構函式
    • parent關鍵字表示父類的名字,可以降低程式的耦合性
# 通過類名呼叫父類的建構函式
父類類名::__construct();

# 通過parent關鍵字呼叫父類的建構函式
parent::__construct();
<?php
class Person {
  //父類的建構函式
  public function __construct() {
    echo '這是父類<br>';
  }
}
class Student extends Person {
  //子類的建構函式
  public function __construct() {
    //通過父類的名字呼叫父類的建構函式
    Person::__construct();
    //parent表示父類的名字		
    parent::__construct();		
    echo '這是子類<br>';
  }
}
new Student();
?>
  • 案例
<?php
class Person {
	protected $name;
	protected $sex;
    //父類的建構函式
	public function __construct($name, $sex) {
		$this->name= $name;
		$this->sex= $sex;
	}
}
class Student extends Person {
	private $score;
    //子類的建構函式
	public function __construct($name, $sex, $score) {
		parent::__construct($name, $sex);  //呼叫父類建構函式並傳遞引數
		$this->score= $score;
	}
    //顯示資訊
	public function getInfo() {
		echo "姓名:{$this->name}<br>";
		echo "性別:{$this->sex}<br>";
		echo "成績:{$this->score}";
	}
}
//測試
$stu=new Student('sunny','男',28);
$stu->getInfo();
?>

$this詳解

  • 概念
    • $this表示當前物件的引用,也就是$this儲存的當前物件的地址
<?php
class A {
	public function __construct(){
		var_dump($this);
	}
}
class B extends A {
	
}
new A();
echo '<br>';
new B();
?>

多重繼承

  • 概念
    • PHP不允許多重繼承,因為多重繼承容易產生二義性
    • 如何實現C繼承A和B,使用繼承鏈

多型

  • 多型分為兩種:方法重寫和方法過載

方法重寫

  • 子類重寫了父類的同名的方法
    • 子類的方法必須和父類的方法同名
    • 引數個數要一致
    • 子類修飾的不能比父類更加嚴格
<?php
class A{
  protected function say($name){
    echo $name,',狗!<br/>';
  }
  protected function says($name){
    echo $name,',狗!<br/>';
  }
}
class B extends A{
  public function say($name){
    echo $name,',貓!<br/>';
  }
}
$per= new B();
$per->say('Sunny');
$per->says('Sunny');
?>

方法過載

  • 方法過載
    • 在同一個類中,有多個同名的函式,通過引數的不同來區分不同的方法
    • PHP不支援方法過載,但是PHP可以通過其他方法來模擬方法過載
<?php 
class Overloader { 
  private $properties= array(); 
  function __get($property_name){ 
    if(isset($this->properties[$property_name])){ 
      return($this->properties[$property_name]); 
    }else{ 
      return(NULL); 
    } 
  } 
  function __set($property_name, $value){ 
    $this->properties[$property_name]= $value; 
  } 
  public function __call($method, $p){ 
    print("Invoking $method()<br>\n"); 
    //print("Arguments: "); 
    //print_r($args); 
    if($method == 'display'){ 
      if(is_object($p[0])) 
        $this->displayObject($p[0]); 
      else if(is_array($p[0])) 
        $this->displayArray($p[0]); 
      else $this->displayScalar($p[0]); 
    } 
  } 
  public function displayObject($p){ 
    echo ("你傳入的是個物件,內容如下:<br>"); 
    print_r($p); 
    echo "<hr>"; 
  } 
  public function displayArray($p){ 
    echo ("你傳入的是個陣列,內容如下:<br>"); 
    print_r($p); 
    echo "<hr>"; 
  } 
  public function displayScalar($p){ 
    echo ("你傳入的是個單獨變數,內容如下:<br>" . $p); 
    echo "<hr>"; 
  } 
} 
$obj= new Overloader(); 
//呼叫 __set() 給一個不存在的屬性變數賦值 
$obj->dynaProp = "Dynamic Content"; 
//呼叫 __get() 
print($obj->dynaProp."<br>\n"); 
//呼叫 __call() 
$obj->dynaMethod("Leon", "Zeev"); 
// $obj->display(array(1,2,3)); 
// $obj->display('Cat'); 
?> 

面向物件三大特性

  • 特性
    • 封裝
    • 繼承
    • 多型