PHP面向對象編程:面向對象概念、基本實踐、高級實戰、PHP面向對象特殊實踐

1、面向對象的概念

1.1 什麼是面向對象(object oriented)

     世間萬物皆對象,抽象的也是對象,一切可見或不可見都是對象php

1.2 對象的基本組成

     對象包含兩個部分:編程

  • 對象的組成元素segmentfault

    • 是對象的數據模型,用於描述對象的數據
      又稱爲對象的屬性,或者對象的成員變量
  • 對象的行爲數組

    • 是對象的行爲模型,用於描述對象可以作什麼事情
      又被稱爲對象的方法

1.3 對象特色

  • 每個對象都是獨一無二的
  • 對象是一個特定的事物,他的職能是完成特定功能
  • 對象是能夠重複使用

1.4 面向對象簡介

  1. 面向對象編程
    就是編程的時候數據結構(數據組織方式 )都經過對象的結構進行存儲,使用屬性方法組織起來
  2. 爲何要使用面向對象編程?
    對象的描述方式更加貼合真實世界,有利於對大型業務的理解

1.5 面向對象的實質

  1. 面向對象就是把生活中要解決的問題都用對象的方式進行存儲--把全部的數據用屬性方法表現出來。
  2. 對象之間的互動是經過方法的調用完成互動

1.6 面向對象的基本思路

  1. 識別對象
    任何實體均可以被識別爲一個對象
  2. 識別對象的屬性
    對象裏面存儲的數據被識別爲屬性
    對於不一樣的業務邏輯,關注的數據不一樣,對象裏面存儲的屬性也不一樣
  3. 識別對象的行爲
    對象本身的屬性數據的改變
    對象外部的交互

1.7 面向對象的基本原則

  1. 對象內部高內聚
    對象只負責一項特定的職能(職能可大可小)
    全部對象相關的內容都封裝到對象內部
  2. 對象外部低耦合
    外部世界能夠看到對象的一些屬性(並不是所有)
    外部世界能夠看到對象能夠作某些事情(並不是所有)

     軟件設計儘量的作到:高內聚,低耦合,模塊與模塊間應該是獨立的,沒有依賴關係數據結構

2、面向對象的基本實踐

2.1 類的概念

  1. 物以類聚,把具備類似特性的對象對壘到一個類中
  2. 類定義了這些類似對象擁有的相同的屬性和方法
  3. 類是類似對象的描述,成爲類的定義,是該類對象的藍圖或者原型
  4. 類的對象稱爲一個類的實例(Instance)
  5. 類的屬性和方法統稱爲類成員

2.2 類的實例化

  • 類的實例化:經過類定義建立一個類的對象
  • 類的定義屬性值都是空或默認值,而對象的屬性都有具體的值

2.3 類的定義

  1. 類的定義以關鍵字class開始,後面跟着這個類的名稱。類的命名一般每一個單詞的第一個字母大寫,以中括號開始和結束
  2. 類的實例化爲對象時使用關鍵字newnew以後緊跟類的名稱和一對括號
  3. 對象中得成員屬性和方法能夠經過->符號來訪問

2.4 構造函數

  1. 默認構造函數在對象被實例化的時候自動調用
  2. $thisPhp裏面的僞變量,表示對象自己。能夠經過$this->的方式訪問對象的屬性和方法
  3. 每一次用new實例化對象的時候,都會用類名後面的參數列表調用構造函數
  4. php類函數的構造函數function __construct(){}運行時自動調用

2.5 析構函數

  1. function __destruct(){}析構函數是根據後入先出的原則
  2. 兩種方式會被執行析構函數:對象被設置未null或者程序結束時會被自動調用析構函數,,所佔用的資源被系統回收
  3. 析構函數一般被用於清理程序使用的資源,好比釋放打開的文件等等
  4. 析構函數在該對象不會再被使用的狀況下自動調用,若是被複制了,而不是&引用,就不會調用析構函數

2.6 對象&引用的基本概念

$james1 = $james; //至關於複製出來多一個引用,二者是獨立的兩個引用
$james2 = &$james; //至關於爲james取一個別名,二者實際上是一體的,只是有兩個名字

clipboard.png

     特別注意:函數

  1. PHP 永遠會將對象按引用傳遞ArrayObject 是一個SPL對象,它徹底模仿數組的用法,可是倒是以對象來工做)
  2. $arr = array(); $arr2 = $arr; $arr2$arr數組的一份拷貝,它們之間互不影響,是獨立的兩個數組
  3. &對象(數組)都是至關於起別名

深刻理解PHP引用:常見錯誤 #3:關於經過引用返回與經過值返回的困惑

3、面向對象的高級實戰

3.1 對象的繼承

    父類:擁有部分相同的屬性和方法this

    繼承的好處spa

  1. 父類裏面定義的類成員能夠不用在子類中重複定義,節約了編程的時間和代價
  2. 同一個父類的子類擁有相同的父類定義的類成員,所以外部代碼調用他們的時候能夠一視同仁
  3. 子類能夠修改和調用父類定義的類成員設計

    • 咱們稱爲重寫Overwrite
    • 一旦子類修改了,就按照子類修改以後的功能執行

    子類:3d

  1. 子類能夠經過$this訪問父類的屬性
  2. 子類的對象能夠直接調用父類的方法和屬性
  3. PHP單繼承特性:類不容許同時繼承多個父類(extends後面只能跟一個父類名稱)

3.2 訪問控制

    面向對象的三種訪問權限:

  1. public是公有的類成員,能夠在任何地方被訪問

    • 能夠被類以及子類或者對象均可以訪問
  2. protected受保護的類成員,能夠被其自身以及繼承的子類訪問

    • 能夠被子類繼承,可是不能被對象訪問,只能經過封裝的方式讓對象訪問
  3. private私有的類成員,只能被自身訪問

    • 不能被子類繼承,也不能被對象訪問,只能在自身經過封裝讓外界訪問(例如在類裏面定義一個公開方法來調用私有屬性)

3.3 Static(靜態)關鍵字

    靜態成員:定義時在訪問控制關鍵字後添加static關鍵字便可(訪問控制關鍵字:public. protected. private

  1. 靜態屬性用於保存類的公有數據,能夠在不一樣對象間共享
  2. 靜態方法裏面只能訪問靜態屬性
  3. 靜態成員不須要實例化對象就能夠訪問
  4. 類的內部能夠經過 self::static:: 關鍵字訪問自身靜態成員,self::$屬性 self::方法()
  5. 經過 parent:: 關鍵字訪問父類的靜態成員,也能夠經過子類::父類靜態成員
  6. 經過 類名:: 的方式在類的外部訪問靜態成員

3.4 重寫和Final關鍵字

  1. 子類中編寫跟父類徹底一致的方法能夠完成對父類方法的重寫,方法參數最好有默認參數
  2. 對於不想被任何類繼承的類能夠在class以前添加final關鍵字
  3. 對於不想被子類重寫(overwrite, 修改)的方法,能夠在方法定義前面添加final關鍵字

3.5 數據訪問

  1. parent關鍵字能夠可用於調用父類中被子類重寫了的方法
  2. self關鍵字能夠用於訪問類自身的成員方法,靜態成員和類常量;不能用於訪問類自身的屬性!!!使用常量的時候不須要在常量const名稱前面添加$符號
  3. static::關鍵字用於訪問類自身定義的靜態成員,訪問靜態屬性時須要在屬性前面添加$符號。
  4. 常量屬性const不能使用對象訪問,僅能使用類訪問,在類本體內可使用「self::常量名」,在類本體外可使用「類名::常量名

3.6 對象接口

     接口就是把不一樣類的共同行爲進行定義,而後在不一樣的類裏面實現不一樣的功能

  1. interface定義接口,implements用於表示類實現某個接口
  2. 接口裏面的方法沒有具體的實現,無{}
  3. 實現了某個接口的類必須提供接口中定義的方法的具體實現
  4. 不能實例化接口,可是可以判斷某個對象是否實現了某個接口。instanceof關鍵字判斷某個對象是否實現了某個接口 $object instanceof interface
  5. 接口能夠繼承接口(interface extends interface
  6. 接口中定義的全部方法必須是公有,這是接口的特性

3.7 多態

     由於接口的方法實現能夠有不少,因此對於接口裏面定義的方法的具體實現是多種多樣的,這種特性咱們稱爲多態

     不須要知道對象屬於哪一個類,只要判斷該對象的類是否實現接口,就能實現調用,相同代碼實現不一樣結果

     形象點說就是同一個接口,不一樣的對象實現,得出的結果不同就是多態,如傳入的是人類對象,獲得的是人類吃蘋果,傳入的是猴子對象,獲得的就是猴子吃香蕉。相同的一行代碼,對於傳入不一樣的接口的實現的對象的時候,表現是不一樣的。

/**
 * 多態
 * 1. 只要某個對象實現了接口(instanceof),就能夠直接在對象上調用接口的方法
 */

interface ICanEat {
   public function eat($food);
}

// Human類實現了ICanEat接口
class Human implements ICanEat { 
  // 跟Animal類的實現是不一樣的
  public function eat($food){
    echo "Human eating " . $food . "\n";
  }
}

// Animal類實現了ICanEat接口
class Animal implements ICanEat {
  public function eat($food){
    echo "Animal eating " . $food . "\n";
  }
}

function eat($obj){
  if($obj instanceof ICanEat){ 
    $obj->eat("FOOD"); // 不須要知道究竟是Human仍是Animal,直接吃就好了
  }else{
    echo "Can't eat!\n";
  }
}

$man = new Human();
$monkey = new Animal();

// 一樣的代碼,傳入接口的不一樣實現類的時候,表現不一樣。這就是爲何成爲多態的緣由。
eat($man);
eat($monkey);

3.8 抽象類

     接口裏面的方法都是沒有實現的,而類裏面的方法都是有實現的。
     有沒有一種形態,容許類裏面一部分方法不實現呢?

  • 當接口中的某些方法對於全部的實現類都是同樣的實現方法,只有部分方法須要用到多態的特性

    • 如人和動物吃東西是不一樣的,可是呼吸是相同的,不須要爲人和動物分別實現呼吸的功能
  1. abstract關鍵字用於定義抽象類
  2. 在抽象方法前面添加abstract關鍵字能夠標明這個方法是抽象方法不須要具體實現{}
  3. 抽象類中能夠包含普通的方法,有方法的具體實現
  4. 繼承抽象類的關鍵字是extends
  5. 繼承抽象類的子類須要實現抽象類中定義的抽象方法
  6. 抽象類不能被實例化,當子類繼承抽象類的時候,全部的抽象的方法都必須定義
/**
 * 抽象類
 * 1. 抽象類容許類裏面的部分方法暫時沒有具體實現,這些方法咱們成爲抽象方法
 * 2. 一旦類裏面有抽象方法,這個類就必須是抽象類
 * 3. 抽象類跟接口同樣,不能直接實例化爲對象
 */

// 抽象類前面以abstract關鍵字開始
abstract class ACanEat {
   // 沒有實現的方法須要設定爲抽象方法
   // 抽象方法須要在子類中實現 
   abstract public function eat($food);

   public function breath(){
      echo "Breath use the air.\n";
   }
}

// Human類實現了ICanEat接口
class Human extends ACanEat { 
  // 跟Animal類的實現是不一樣的
  public function eat($food){
    echo "Human eating " . $food . "\n";
  }
}

// Animal類實現了ICanEat接口
class Animal extends ACanEat {
  public function eat($food){
    echo "Animal eating " . $food . "\n";
  }
}

$man = new Human();
$man->eat("Apple");
$man->breath(); // 和Animal共用了抽象類ICanEat的breath方法
$monkey = new Animal();
$monkey->eat("Banana");
$monkey->breath();

4、PHP面向對象的特殊實踐

4.1 魔術方法之_toString()和invoke()

  1. __toString()當對象被看成String使用時,這個方法會被自動調用(須要在類中定義__tostring()方法。調用 echo $object
  2. __invoke()當對象被看成方法調用時,這個方法會被自動調用(須要在類中定義__invoke()方法)。調用 $object($parameter)
/**
 * 魔術方法1
 * 1. 當對象被當作String使用時,__toString()會被自動調用
 * 2. 當對象被當成方法調用時,__invoke()會被自動調用
 */
class MagicTest{
  public function __toString(){
    return "This is the Class MagicTest.\n";
  }
  public function __invoke($x){
    echo "__invoke called with parameter " . $x . "\n";
  }
}

$obj =  new MagicTest();
echo $obj;
$obj(5);

4.2 魔術方法之__call()和__callStatic()

  1. __call()方法:當對象訪問不存在的方法名稱時,此方法自動調用。

    • 調用示例:public function __call($name,$argument){}
    • 注意:訪問控制關鍵字必須爲public;必須有兩個參數:對象訪問的方法名稱($name)、方法包含的參數($argument ==> 自動轉換成數組)。
  2. __callStatic()方法:當對象訪問不存在的靜態方法名稱時,此方法自動調用。

    • 調用示例:public static function __callStatic($name,$argument){}
    • 注意:同__call();此方法爲靜態方法(static)。
  3. 這兩種方法也被稱爲方法的重載overloading

    • 注意區分重寫(overwrite
    • 經過這兩個方法,同一個方法的調用能夠對應不一樣的方法的實現(同一個方法的靜態調用、動態調用對應不一樣的方法實現)
/**
 * 魔術方法之方法重載
 * 1. 當對象訪問不存在的方法名稱時,__call()方法會被自動調用
 * 2. 當對象訪問不存在的靜態方法名稱時,__callStatic()方法會被自動調用
 */
class MagicTest{
    /**
     * 自動將參數轉換成數組
     * array (size=2)
     *  0 => string 'para1' (length=5)
     *  1 => string 'para2' (length=5)
     * @param $name
     * @param $arguments
     */
  public function __call($name, $arguments){
      var_dump($arguments);
    echo "Calling " . $name . " with parameters: " . implode(', ', $arguments) . "\n";
  }

  public static function __callStatic($name, $arguments){
    echo "Static calling " . $name . " with parameters: " . implode(', ', $arguments) . "\n";
  }
}

$obj =  new MagicTest();
$obj->runTest("para1", "para2");
MagicTest::runTest("para3","para4");

4.3 魔術方法之__get()、__set()、__isset()和__unset()

  1. 在給不可訪問屬性賦值時,__set()會被調用 定義function __set($name,$value)
  2. 讀取不可訪問屬性的值時,__get()會被調用 定義function __get($name)
  3. 當對不可訪問屬性調用isset()empty()時,__isset()會被調用
  4. 當對不可訪問的屬性調用unset()時,__unset()會被調用

     這幾個方法也被成爲屬性重載的魔術方法
     所謂不可訪問屬性,實際上就是在調用某個屬性時發現這個屬性沒有被定義,這時候不一樣的操做會觸發不一樣的魔術方法

4.4 魔術方法之__clone()

clipboard.png

$obj1 = $ojb; //不能實現對象複製,兩個對象變量指向同一對象
$obj1 = clone $obj; //實現對象複製,變成值相同的兩個對象

     調用clone時會自動調用__clone()方法

$james = new NbaPlayer(); //$ja0 對應內存地址(假設爲 address0 )中存儲的是 james對象的標識符
$james2 = clone $james;    //當但願生成一個真正獨立存儲的 NbaPlayer() 對象,但新對象的全部數據都和 $james 對象中的相同時,使用關鍵字clone

     當在class NbaPlayer()中定義了 __clone()方法 後,使用clone關鍵字時,系統將調用用戶定義的__clone()方法 (此時能夠對clone後生成的新對象的屬性進行修改)

完!

參考教程:PHP面向對象編程

相關文章
相關標籤/搜索