php物件導向個人濃縮總結和例項

蜻蜓隊長dragonfly429發表於2019-03-07

大概1年前我總結過,但是那時候太菜,現在我又來總結了。 (本文是總結,不是入門,剛學oop的不適合看,基礎寫的比較省略。)


0.思路

其實oop程式設計發展到現在,知識點很多,而且很雜,比如static就很亂,很容易混淆,我自己這麼分類:

  • 1.類和物件(建立類和物件的基本概念)
  • 2.層級組織及其衍生(完善和增強類,建立層級,便於組織和複用程式碼)
  • 3.其他工具和特性(各個語言都有的攔截器,序列化,php有的魔術方法等雜項)

1.類和物件

1.1類和物件的概念

類和物件是模擬現實中,一群相似的物體,以及他們的抽象模板的關係,在程式設計中便於將方法(功能)和屬性(資料)組織到一起,做到封裝,解耦,提高程式碼的健壯性和複用性。 是一個非常重要的概念發明。

類和物件的基本概念一言難盡,總結:

  • 類的由屬性和方法組成
  • 屬性和方法可以呼叫
  • 類可以例項化(new)出物件

1.2可見性

屬性和方法,都有三種可見性,分別用三個單詞去修飾

在類的外部可訪問 子類可訪問
public Y Y
protected N Y
private N N

1.3static作用域

類由屬性和方法組成,屬性和方法可以呼叫,一個類例項化成多個物件後,每個物件都有自己的屬性和方法,而且呼叫同樣的方法後結果不一定一樣,這叫多型。

然而屬性和方法不一定要例項化後才能呼叫,定義為static的屬性和方法就是直接可以呼叫,無需例項化。

我這麼理解,類是一個特殊的作用域,就當成一個特殊的物件,他持有靜態屬性和靜態方法,物件也可以呼叫靜態方法,但是類不能呼叫非靜態方法。

物件改變靜態屬性的值後,當物件銷燬了,靜態屬性的值還在,因為他屬於類。

1.4自動載入

使用類前必須定義類,當前檔案沒有這個類,就要include,當應用變大,就會很難搞。 就要用到自動載入。

自動載入就是依靠spl_autoload_register()實現,引數是一個函式,當找不到使用的類的時候,就會將類名作為引數傳入註冊的函式。

<?php
spl_autoload_register(function($class_name){
    require_once 'www/app/lib/'.$calss_name.'.php';
})
複製程式碼

1.5建構函式

建構函式是最重要的一個魔術方法,所以提前單說。

2.層級設計及其衍生

發明類和物件的關係已經很厲害了,但是還不夠,為了處理更加複雜的關係,出現了物件層級。

一個物件可以繼承另一個物件,這樣可以更好得組織程式碼和複用程式碼。然後還有抽象類,介面和trait都是oop中組織和複用程式碼的工具。

2.1繼承和過載

  • 一個物件可以繼承另一個物件,這樣他就具有了父物件的屬性和方法
  • 子物件可以覆蓋父物件的方法
  • 呼叫時優先在子物件尋找屬性和方法,沒有就去父類尋找
  • 被final修飾的屬性和方法無法過載

2.2抽象類 介面 trait

  • 抽象類的程式碼是側重規範性而非實現功能,跟虛擬碼有點像,他定義要實現哪些函式,但是不寫具體實現。
  • 介面跟抽象類很像,但是抽象類只能單繼承,介面可以多繼承。
  • triat則是程式碼片段的複用。

一言難盡,直接說重點

是否多繼承 程式碼是有功能性的還是規範性的
N 功能
抽象類 N 規範(主要)和功能
介面 Y 規範
trait Y 功能(主要)和規範

注意

  • 1.抽象類
    • 只要類中有抽象方法,就必須定義為抽象類,同時裡面可以有非抽象方法
  • 2.介面
    • 介面的的方法都是public的,並且是沒有內容的, 介面可以有常量
    • 介面還可以繼承介面,擴充套件
  • 3.trait
    • 可以有屬性、方法、可以是靜態的,
    • 甚至可以寫抽象方法,
    • trait還可以包含trait,
    • 匯入trait的時候還能更改裡面方法的可見性

2.3各種組合下的呼叫屬性和方法

靜態非靜態*內外部+常量

class ClassA{
	//屬性
	public  $var1 = 1;
	//靜態屬性 靜態就是歸類管,不歸物件管
	public static $var2 = 2;
	//常量 常量不可更改 訪問方式類似靜態
	const VAR3 = 3;
	//非靜態方法
	public function m1(){
		echo 'm1 working ......';
		echo PHP_EOL;
		//引入$this和self
		//類內訪問正常屬性 不用加$
		echo $this->var1;
		echo PHP_EOL;
		//類內訪問靜態屬性 要加$ 用類名也行
		echo self::$var2;
		echo ClassA::$var2;
		echo PHP_EOL;
		//類內訪問常量 就用類名 self也行
		echo ClassA::VAR3;
		echo self::VAR3;
		echo PHP_EOL;
	}
	//靜態方法
	public static function m2(){
		echo 'm2 working ......';
		echo PHP_EOL;
		//靜態方法不能訪問非靜態屬性或方法,因為沒有例項,$this沒意義
		// echo $this->var1; //Fatal error: Uncaught Error: Using $this when not in object context
		// echo PHP_EOL;
		//類內訪問靜態屬性 要加$ 用類名也行
		echo self::$var2;
		echo ClassA::$var2;
		echo PHP_EOL;
		//類內訪問常量 就用類名 self也行
		echo ClassA::VAR3;
		echo self::VAR3;
		echo PHP_EOL;
	}
}
//呼叫非靜態方法 
(new ClassA())->m1();
//呼叫靜態方法 
ClassA::m2();
//測試在類外,呼叫屬性
echo '----------';
echo PHP_EOL;
//非靜態屬性
echo (new ClassA())->var1;
echo PHP_EOL;
//靜態屬性
echo ClassA::$var2;
echo PHP_EOL;
//常量  
echo ClassA::VAR3;
echo PHP_EOL;
複製程式碼

非靜態 訪問控制 過載和訪問父級

/*非靜態 訪問控制 過載和訪問父級*/
class ClassA{
	//屬性
	public  	$var1 = 1;
	protected  	$var2 = 2;
	private  	$var3 = 3;
	//方法
	public function m1(){
		echo 'm1 working ......';
		echo $this->var1;
		echo $this->var2;
		echo $this->var3;
		echo PHP_EOL;
	}
	protected function m2(){
		echo 'm2 working ......';
		echo $this->var1;//發現還是4 過載就就覆蓋了 沒有方法那樣的保持層級
		echo PHP_EOL;
	}
	private function m3(){
		echo 'm3 working ......';
		echo PHP_EOL;
	}
}
$obj1 = new ClassA();
$obj1->m1();
//$obj1->m2();//Fatal error: Uncaught Error: Call to protected method ClassA::m2() 
//$obj1->m3();//Fatal error: Uncaught Error: Call to private method ClassA::m3()
echo '--------------------';
echo PHP_EOL;
class ClassB extends ClassA{
	//屬性 這裡叫過載
	public  	$var1 = 4;
	private  	$var3 = 6;
	//方法 過載m1
	public function m1(){
		echo 'm1 working ......';
		echo $this->var1;
		//echo parent::var1;//這是錯誤的 只有靜態才能這樣呼叫
		echo $this->var2;//沒有過載就呼叫父類的屬性
		echo $this->var3;
		echo PHP_EOL;
	}
	//過載m2
	public function m2(){
		echo 'class B m2 working ......';
		// echo parent::$var1; 屬性沒有這種呼叫,如果沒有
		echo PHP_EOL;
		parent::m2();
	}
	public function m4(){
		echo 'm4 working ......';
		// $this->m3();//Fatal error: Uncaught Error: Call to private method ClassA::m3() 
	}
}
$obj2 = new ClassB();
$obj2->m1();
$obj2->m2();
$obj2->m4();
複製程式碼

靜態 訪問控制 過載和訪問父級

/*靜態 訪問控制 過載和訪問父級*/
class ClassA{
	//屬性
	public  static	$var1 = 1;
	protected  static	$var2 = 2;
	private  static	$var3 = 3;
	//方法
	public static function m1(){
		echo 'm1 working ......';
		echo self::$var1;
		echo self::$var2;
		echo self::$var3;
		echo PHP_EOL;
		self::m2();
	}
	protected static function m2(){
		echo 'm2@A working ......';
		echo PHP_EOL;
	}
	private static function m3(){
		echo 'm3 working ......';
		echo PHP_EOL;
	}
}
echo ClassA::$var1;
echo PHP_EOL;
// echo ClassA::$var2;//Fatal error: Uncaught Error: Cannot access protected property ClassA::$var2
ClassA::m1();
// ClassA::m2();//Fatal error: Uncaught Error: Call to protected method ClassA::m2() 
//$obj1->m2();//Fatal error: Uncaught Error: Call to protected method ClassA::m2() 
echo '--------------------';
echo PHP_EOL;
class ClassB extends ClassA{
	//屬性  過載
	public  static	$var1 = 4;
	//方法 過載m1
	public static function m1(){
		echo 'm1@B working ......';
		echo self::$var1;
		echo parent::$var1;
		echo self::$var2;
		// echo self::$var3;//Fatal error: Uncaught Error: Cannot access  property ClassB::$var3
		echo PHP_EOL;
		self::m2();
		parent::m2();
	}
	protected static function m2(){
		echo 'm2@B working ......';
		echo PHP_EOL;
	}
	 
}
ClassB::m1();

複製程式碼

3.其他

  • 魔術方法
    • 常用8
      • __construct() __destruct(),
      • __call() __callStatic(),
      • __get() __set() __isset() __unset(),
    • 不常用4
      • __sleep() __wakeup(),
      • __toString(),
      • __invoke(),
    • 我不會3
      • __set_state(),
      • __clone()
    • __debugInfo()
  • 相關函式
    • get_class()
    • instanceof ()
    • ::class
  • 物件操作
    • 物件序列化
    • 物件比較
    • 物件遍歷
    • 物件複製
  • 其他
    • 型別約束
    • 應用的理解
    • 匿名類
    • static延遲繫結

魔術方法

1 __construct() __destruct() 構建和析構方法,在建立和銷燬物件時呼叫
2 __call() __callStatic() 呼叫不存在的方法時呼叫
3 __set(),__get(),__isset(),__unset() 攔截器系列
4 __sleep() __wakeup() 在serialize()unserialize()時呼叫,可以額外加一些邏輯
5 __toString() 在echo時呼叫,不定義就echo會error
6 __invoke() 當以函式方式呼叫物件時啟動
7 __set_state() __debugInfo() 我也不知道有啥用
8 __clone() 自定義如何複製物件
/*魔術方法2*/
/*sleep wakeup invoke toString*/
class B{
	function __construct($name,$age){
		$this->name = $name;
		$this->age = $age;
	}
	function __sleep(){
		echo $this->name.'is sleep';
		echo PHP_EOL;
		return array('name','age');
	}
	function __wakeup(){
		echo $this->name.'is wakeup';
		echo PHP_EOL;
	}
	function __toString(){
		return  'i am '.$this->name;
	}
	function invoke($arg){
		echo 'what are u doing';
		echo PHP_EOL;
	}
}
//sleep
$obj = new B('hahaha','19');
$data = serialize($obj);
var_dump($data);
$test = unserialize($data);
//tostring
echo $test;
//invoke
$test('111');
/*魔術方法1*/
/*構建 析構 call get*/
class A{
	public $name = 'default';
	public $data = [];
	//構建方法
	public function __construct($name=NULL){
		if($name){
			$this->name = $name;
		}
		echo '__construct runing.....';
		echo PHP_EOL;
	}
	//析構方法
	public function __destruct(){
		echo '__destruct runing.....';
		echo PHP_EOL;
	}
	//攔截器
	public function __call($name,$arguments){
		echo 'you are try to run method'.$name.'but its not exists';
		echo PHP_EOL;
	}
	public static function __callStatic($name,$arguments){
		echo 'you are try to run static method'.$name.'but its not exists';
		echo PHP_EOL;
	}
	//獲取器設定器
	public function __set($name,$value){
		$this->data[$name] = $value;
		echo 'setter runing ';
		echo PHP_EOL;
	}
	public function __get($name){
		if(isset($this->data[$name])){
			return  $this->data[$name];
		}else{
			return 'empty';
		}
	}
	public function __isset($name){
		if(isset($this->data[$name])){
			echo 'Y';
		}else{
			echo 'N';
		}
		echo PHP_EOL;	
	}
	public function __unset($name){
		if(isset($this->data[$name])){
			unset($this->data[$name]);
		}
		echo 'done ';
		echo PHP_EOL;	
	}
}
$obj = new A('xyz');
echo $obj->name;
echo PHP_EOL;
$obj->tag = 'mmmm';
echo $obj->tag;
echo PHP_EOL;
echo $obj->bag;
echo PHP_EOL;
echo $obj->run();
echo PHP_EOL;
echo A::fly();
echo PHP_EOL;
複製程式碼

static有兩種意思

  • 1.區分作用域在類還是物件,靜態變數是類作用域
  • 2.有“最初呼叫類”的意思,主要2個用法,
    • new static,
    • 和延遲靜態繫結static::funct()

相關文章