溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP面向對象特性有哪些

發布時間:2020-10-29 14:06:47 來源:億速云 閱讀:196 作者:小新 欄目:編程語言

小編給大家分享一下PHP面向對象特性有哪些,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

面向對象的三個主要特性是封裝、繼承和多態。

創建對象

$對象名 = new 類名();
$對象名 = new 類名;
  • new 是一個關鍵字,表示創建一個新的實例。
  • 在類定義內部,可以用 new selfnew parent 創建新對象。

成員屬性

成員屬性必須要有訪問修飾符,如果不寫,會報錯。

成員屬性的默認值為NULL。

示例:

class Test {
    
    public $name; //共有
    protected $height; //保護
    private $age; //私有
}

成員方法

成員方法如果不寫訪問修飾符,則默認為public。

我們可以指定成員方法里的參數的類型,如 類類型,或者數組類型(array),也可以是接口類型,但是接口類型要注意,因為接口沒有實例,當我們聲明參數類型為接口類型的時候,那么傳入的參數只要是實現了該接口的類的實例即可。

示例:

class Test {
    
    function hello() {} //默認為public
    public function say() {} //公有
    protected function smile() {} //保護
    private function laugh() {} //私有
}

構造方法

  • 一個類里只能有一個構造方法。
  • 沒有返回值(即使在構造方法里寫了返回值也沒有意義)
  • 在創建一個類的新對象時,系統會自動的調用類的構造方法完成對新對象的初始化。
  • 如果我們沒有重寫默認構造函數,那么系統會默認幫我們創建一個沒有參數的構造函數,public function __construct(){},如果我們重寫了構造函數,那么我們自定義的構造函數就會覆蓋系統默認的構造函數。
  • 如果我們自定義的構造函數里有行參,那么當我們創建對象的時候就必須傳入相應的實參。否則會報錯。

示例:

class Test {

    public function __construct() {
        echo 'hello, world<br>';
    }
}

$testObj = new Test();


class One {

    public function __construct($param) {

        echo $param;
    }
}

$oneObj = new One('hello, world<br>');

輸出結果:

hello, world
hello, world

析構方法

  • 當一個對象沒有被任何變量引用時就會自動銷毀,并在被銷毀前自動調用析構函數,無論程序有沒有結束,只要一個對象沒有被任何變量引用就會被銷毀。
  • 當PHP程序運行結束后,所有的對象都會被銷毀,對象在被銷毀前,會自動調用析構函數。
  • 默認情況下,析構函數銷毀對象的順序和創建對象的順序正好相反。最先創建的對象最后被銷毀,強調默認情況下是因為,我們可以手動銷毀對象,這樣的話對象銷毀的順序就和默認情況不一樣了,當PHP程序執行完后,那時候銷毀對象的方法就是采用的默認方法。
  • 如果我們定義的一個類里專門有個屬性是用來連接數據庫的,當我們創建了該類的實例對象,并且用該成員屬性連接數據庫后,如果該類型的實例對象占用資源較大,我們往往會在使用后就立即銷毀,雖然該對象能被銷毀,但是該對象的成員屬性所連接的資源卻不會被自動銷毀,需要我們自己手動銷毀,這時,我們可以在析構函數里添加一句關閉數據庫連接的語句就好了(mysql_close(要關閉的資源))。

示例:

class Test {

    public function __construct() {
        echo 'hello, world<br>';
    }

    public function __destruct()
    {
        echo '執行一些回收資源的操作<br>';
    }
}

$testObj = new Test();

輸出結果:

hello, world
//執行一些回收資源的操作

垃圾回收機制

  • 在PHP中,當一個對象沒有任何引用指向它的時候,就會成為一個垃圾對象,PHP將啟用垃圾回收器將對象銷毀。
  • 在PHP程序退出前,PHP也將啟用垃圾回收器,銷毀對象。

訪問修飾符

  • public

    如果沒有為方法指定訪問修飾符,它將是public。公有的屬性或方法可以在類的內部或外部進行訪問。

  • protected

    如果一個屬性或方法指定訪問修飾符為protected,那么被標記的屬性或方法只能在類內部訪問,被修飾的屬性和方法能被子類繼承。

  • private

    如果一個屬性或方法指定訪問修飾符為private,那么被標記的屬性或方法只能在類內部訪問,私有的屬性和方法將不會被繼承。

魔術方法

  1. 魔術方法都是在滿足某個條件時,由系統自動調用。

  2. 魔術方法的名字,都是以兩個下劃線(__)開頭的,因此我們在自定義函數時,函數名不要以兩個下劃線開頭。

  3. 一些常用的魔術方法

    __construct():
     構造方法
    __destruct():
     析構方法
    __set():
     在給不可訪問屬性賦值(比如:protected/private/不存在)時,__set()會被調用。
    __get():
     讀取不可訪問屬性的值(比如:protected/private/不存在)時,__get()會被調用。
    __isset():
     當對不可訪問屬性(比如:protected/private/不存在)調用isset()或empty()時,__isset()會被調用。
    __unset():
     當對不可訪問屬性(比如:protected/private/不存在)調用unset()時,__unset()會被調用。
    __toString():
     當我們把一個對象當做字符串輸出時,就會自動調用__stoString()方法。
    __clone():
     如果定義了__clone方法,則新創建的對象clone(復制生成的對象)中的__clone()會被調用。用法如下:
     $copy_of_object = clone $object;
     克隆后的對象與原對象的地址不一樣。
     當對象被復制后,PHP 5 會對對象的所有屬性執行一個淺復制(shallow copy)。所有的引用屬性 仍然會是一個指向原來的變量的引用。
     如果想防止其他程序員克隆某個對象,可以重寫__clone()方法并把訪問修飾符設置為private。
    __call():
     在對象中調用一個不可訪問(比如函數訪問修飾符為protected/private/不存在)方法時,__call()會被調用。
    __callStatic():
     用靜態方式中調用一個不可訪問方法時,__callStatic() 會被調用。

對象比較

當使用比較運算符(==)比較兩個對象變量時,比較的原則是:如果兩個對象的屬性和屬性值 都相等,而且兩個對象是同一個類的實例,那么這兩個對象變量相等。

而如果使用全等運算符(===),這兩個對象變量一定要指向某個類的同一個實例(即同一個對象)。

示例:

class Test {

    public $name = 'itbsl';
    public $age  = 25;
}

$testObj  = new Test();
$testObj2 = new Test();

if ($testObj == $testObj2) {
    echo '相等<br>';
} else {
    echo '不相等<br>';
}

$testObj2->name = 'jack';

if ($testObj == $testObj2) {
    echo '相等<br>';
} else {
    echo '不相等<br>';
}

繼承

即使父類的某些屬性設置為私有的,子類仍然能夠繼承,但是對子類卻是不可見的。當子類對象使用父類的私有屬性的時候,會自動觸發重載機制,在子類創建一個和父類私有屬性同名的屬性。此時子類使用的屬性并不是父類的私有屬性了,而是通過重載創建的和父類私有屬性同名的屬性罷了。

如果在子類中需要訪問其父類的構造方法( 方法的訪問修飾符是public/protected)可以使用父類::方法名(或者 parent::方法名)來完成。(推薦使用parent::方法名,并且一般調用父類構造方法都是parent::__construct();)

調用父類的普通方法直接用this->方法名即可。(也可以用父類名::方法名或者 parent::方法名 ,但是不推薦)

繼承并不是直接把父類的屬性和方法直接拷貝到子類里面來。而是建立了一種關聯。原本我以為是直接把父類的屬性和方法直接拷貝過來,最后發現只是建立了一種關聯。下圖證明了不是直接拷貝,當在子類里調用父類的方法時,父類輸出自己的屬性時輸出結果都和初始化不一樣了(private屬性除外,因為是私有的,子類無法看見,所以子類也無法重寫父類的私有屬性),如果是直接拷貝的話,那么當調用父類的方法時應該輸出100,200,300才對,所以說繼承不是直接拷貝。

class A {

    public    $num1 = 100;
    protected $num2 = 200;
    private   $num3 = 300;

    public function show1() {
        echo 'num1 = ' . $this->num1 . '<br>';
    }

    public function show2() {
        echo 'num2 = ' . $this->num2 . '<br>';
    }

    public function show3() {
        echo 'num3 = ' . $this->num3 . '<br>';
    }
}

class B extends A {

    public    $num1 = 1;
    protected $num2 = 2;
    private   $num3 = 3;

    public function show1() {
        echo 'num1 = ' . $this->num1 . '<br>';
        parent::show1();
    }

    public function show2() {
        echo 'num2 = ' . $this->num2 . '<br>';
        parent::show2();
    }

    public function show3() {
        echo 'num3 = ' . $this->num3 . '<br>';
        parent::show3();
    }
}

$bObj = new B();
$bObj->show1();
$bObj->show2();
$bObj->show3();

輸出結果:

num1 = 1
num1 = 1
num2 = 2
num2 = 2
num3 = 3
num3 = 300

重載

PHP所提供的"重載"(overloading)是指動態地"創建"類屬性和方法。我們是通過魔術方法(magic methods)來實現的。

當調用當前環境下未定義或不可見的類屬性或方法時,重載方法會被調用。本節后面將使用"不可訪問屬性(inaccessible properties)"和"不可訪問方法(inaccessible methods)"來稱呼這些未定義或不可見的類屬性或方法。

屬性重載只能在對象中進行。在靜態方法中,這些魔術方法將不會被調用。所以這些方法都不能被聲明為 static。從 PHP5.3.0 起, 將這些魔術方法定義為 static 會產生一個警告。

所有重載方法都必須被聲明為public。

這些魔術方法都參數都不能通過引用傳遞。

PHP中的"重載"與其它絕大多數面向對象語言不同。傳統的"重載"是用于提供多個同名的類方法,但各方法的參數類型和個數不同。

因為PHP處理賦值運算的方式,__set()的返回值將被忽略。類似的,在下面這樣的鏈式賦值中,__get()不會被調用。

$a = $obj->b = 8;

在除 isset() 外的其它語言結構中無法使用重載的屬性,這意味著當對一個重載的屬性使用 empty() 時,重載魔術方法將不會被調用。

為避開此限制,必須將重載屬性賦值到本地變量再使用 empty()。

//在對象中調用一個不可訪問方法時,__call() 會被調用。
public mixed __call(string $name , array $arguments)

//用靜態方式中調用一個不可訪問方法時,__callStatic() 會被調用。
public static mixed __callStatic(string $name , array $arguments)

屬性重載

我們曾經提過,當我們訪問或給一個不可訪問(protected/private)的屬性或者不存在的屬性賦值時,就會調用相應的系統魔術方法__get($property)、__set($property, $value),如果我們不重寫這兩個方法,當我們給不存在的屬性賦值時,系統會自動幫我們創建一個public的屬性,我們可以自己重寫這兩個方法來管理這些這些動態創建的屬性?;蛘咧苯硬蛔尞a生動態屬性。當我們不重寫這兩個方法就不可訪問屬性賦值時,會報致命錯誤。

示例:

class Obj {

    protected $name = 'itbsl';



}

$obj = new Obj();
$obj->name = "jack"; //此處會報致命錯誤

var_dump($obj);

錯誤信息為:

Fatal error: Uncaught Error: Cannot access protected property Obj::$name

當我們重寫了__set()方法就沒問題了

class Obj {

    protected $str = 'itbsl';

    public function __set($name, $value)
    {
        $this->$name = $value;
    }

}

$obj = new Obj();
$obj->str = "jack";

var_dump($obj);

屬性重載可以幫助我們動態管理新的屬性也可以禁止動態創建屬性。

(1)動態管理

class Dog {

    //定義一個數組,管理我們動態增加的屬性和值
    private $arr = [];
    
    //這里我們重寫__set來管理動態增加的屬性
    public function __set($name, $value)
    {
        $this->arr[$name] = $value;
    }
    
    public function __get($name)
    {
        return isset($this->arr[$name]) ? $this->arr[$name] : null;
    }
}

(2)禁止創建動態屬性。重寫set方法,里面什么也不做。

class Dog {
    
    //這里我們重寫__set來管理動態增加的屬性
    public function __set($name, $value)
    {
       //just do nothing
    }  
}

方法重寫

在子類中重寫父類的方法時要,重寫的方法的訪問控制符不能比父類的方法的訪問控制符的級別小。例如:如果父類的訪問控制符為public,則子類重寫方法的訪問修飾符只能為public,如果父類的為protected,則子類的訪問修飾控制符可以為protected或public。重寫屬性也要遵守上面的規則。

屬性重寫

如果子類有和父類相同的屬性,如果屬性是public或者protected則會重寫父類的屬性,如果是private則創建一個同名的新私有屬性,同時仍然會繼承父類的同名私有屬性。

靜態屬性

  1. 靜態屬性不屬于某個對象,而是所有對象共享的屬性,每個對象都可以訪問它。
  2. 靜態屬性屬于類的范疇,而不是某個對象的獨有特性。
  3. 在類中,使用和訪問靜態變量的方式是 self::$靜態屬性。
  4. 在類外,使用和訪問靜態變量的方式是 類名::$靜態屬性(要求訪問修飾符為public)。
  5. 當我們用var_dump()輸出一個對象的時候,該對象的靜態變量不會被輸出。
  6. 就像其它所有的 PHP 靜態變量一樣,靜態屬性只能被初始化為文字或常量,不能使用表達式。所以可以把靜態屬性初始化為整數或數組,但不能初始化為另一個變量或函數返回值,也不能指向一個對象。

靜態方法

  1. 靜態方法的訪問方式為 類名::靜態方法名(); 同時也可以用對象名->靜態方法名();和對象名::靜態方法名(),但是后兩種不推薦,盡量只用第一種。
  2. 在類的外部調用靜態方法,要求靜態方法的訪問修飾符必須是public的。
  3. 在類內部調用靜態方法: self::靜態方法 或者 類名::靜態方法 通過$this也可以。只推薦第一種方式。在類的內部訪問靜態方法,無論是什么修飾符都可以訪問靜態方法。
  4. 靜態方法中不可以訪問非靜態屬性和非靜態方法。
  5. 普通的成員方法,可以訪問靜態屬性。

靜態屬性和普通屬性的區別:

(1)加上static稱靜態變量,否則就是普通屬性

(2)靜態屬性是與類相關的,所有對象共享的屬性

(3)普通屬性屬于每個對象個體的屬性。

多態

由于PHP變量沒有類型限制,所以PHP是天生支持多態的。

類型約束

類型約束支持的類型有 array 、 callable 、 對象類型 、 接口

抽象類

當父類的一些方法不能確定時,可以用abstract關鍵字來修飾該方法[抽象方法],用abstract來修飾該類[抽象類]。

(1) 如果你希望把某個方法做成 抽象方法 ,則前面寫上 abstract

(2) 如果一個類中有抽象方法,那么該類必須聲明為抽象類。

(3) 抽象類最主要的作用在于設計,它的目的是讓其它的類繼承它,并實現其中的抽象方法。如果子類繼承了該抽象類,除非繼承該抽象類的子類也被聲明為抽象類,否則必須實現抽象類中所有的抽象方法,如果不實現就會報錯。

(4) 抽象類不能被實例化

(5) 抽象類可以沒有abstract方法

(6) 抽象類可以有非抽象方法,成員屬性和常量

(7) 抽象方法不能有函數體

基本語法:

abstract class 類名 {
    abstract 修飾符 function 函數名(參數列表);
}

普通類如何繼承抽象類?

abstract class Superman {
    public $name;
    public $age;
    
    public function __construct($name, $age) {
        
        $this->name = $name;
        $this->age  = $age;
    }
    
    abstract public function run();
    abstract public function fly();
    abstract public function attach();
}

class Spiderman extends Superman {
    
    public function run()
    {
        echo 'Spiderman is running on the net.<br>';
    }
    
    public function fly()
    {
        echo 'Spiderman can hang in the sky through net.<br>';
    }
    
    public function attach()
    {
        echo 'Spider attach.<br>';
    }
}

接口

(1) 接口就是給出一些沒有實現的方法,封裝到一起,到某個類要使用的時候,再根據具體情況把這些方法寫出來。

(2)基本語法:

interface 接口名 {
    //方法[不含方法體]
}

(3)接口中所有的方法都不能有主體

(4)一個類可以實現多個接口,接口名之間用逗號隔開

class 類名 implements 接口1, 接口2 {
    
}

(5)接口中可以有屬性,但只能是常量,并且是公開可訪問的。默認是public,但不能用public顯式修飾

(6)接口中的方法都必須是public的,默認就是public

(7)一個接口不能繼承其它的類,但是可以繼承別的接口,而且一個接口可以繼承多個接口

interface 接口名 extends 接口1, 接口2 {
    //方法[不含方法體]
}

(8)接口不能被實例化

(9)接口是更加抽象的抽象類,接口里的所有方法都沒有方法體。接口體現了程序設計的多態和高內聚低耦合的設計思想。

(10)說明:

接口的命名規范一般是字符 i 開頭,然后第二個字符大寫,形式如:iXxxx,比如:iUsb

(11)如何使用接口中的常量

接口名::常量名;

如果某個類要實現接口,需要用implements 關鍵字。并且實現接口里的所有方法,如果該類要實現多個接口,則所有的接口的所有的方法都要實現,只要存在沒有實現的接口里的方法就會報錯。

示例:

interface Displayable {
    function display();
}

class Base {
    function operation() {
        echo 'operate something.<br>';
    }
}

class SubClass extends Base implements Displayable {

    function display()
    {
        echo 'display.<br>';
    }
}

$temp = new SubClass();
$temp->display();

final關鍵字

(1) 作用:

因為安全的考慮,類的某個方法不允許子類通過重寫來修改。

不希望某個類被其它的類繼承。

(2) PHP5新增了一個final關鍵字。如果父類中的方法被聲明為final,則子類無法覆蓋該方法。如果一個類被聲明為final,則該類不能被繼承。

(3) final不能夠修飾成員屬性(變量)

(4) final方法不能被重寫,但可以被繼承。即使是被聲明為final的方法也依然能夠被繼承并被使用,只是不能重寫(修改)罷了。

(5) 一般來說,final類中不會出現final方法,因為final類都不能被繼承,也就不會去重寫override final類的方法了。

(6) final類是可以被實例化的。

類常量

可以把在類中始終保持不變的值定義為常量。在定義和使用常量的時候不需要使用 $ 符號。

常量的值必須是一個定值,不能是變量、類屬性、數學運算的結果或函數調用。

接口(interface)中也可以定義常量。更多示例見文檔中的接口部分。

自 PHP 5.3.0 起,可以用一個變量來動態調用類。但該變量的值不能為關鍵字(如 self,parentstatic)。

細節說明:

(1) 常量名一般字母全部大寫:TAX_RATE,中間可以有下劃線

(2) 在定義常量的同時,必須賦初值,比如 const TAX_RATE = 1.1

(3) const關鍵字前不能用public/protected/private修飾。默認是public

(4) 訪問常量

在類的外部 類名::常量名 接口名::常量名

在類的內部 類名::常量名 self::常量名

(5) 常量的值在定義的時候就初始化,以后就不能修改

(6) 常量可以被子類繼承

(7) 一個常量是屬于一個類的,而不是某個對象的。

(8) 常量是全局性的,可以在任何地方訪問。

(9) 在類里面不能用define定義常量。

(10) 常量的值可以是基本類型數據和數組。不可以是對象。

對象遍歷

foreach用法和之前的數組遍歷是一樣的,只不過這里遍歷的key是屬性名,value是屬性值。在類外部遍歷時,只能遍歷到public屬性的,因為其它的都是受保護的,類外部不可見。

示例:

class HardDiskDrive {

    public $brand;
    public $color;
    public $cpu;
    public $workState;

    protected $memory;
    protected $hardDisk;

    private $price;

    public function __construct($brand, $color, $cpu, $workState, $memory, $hardDisk, $price) {

        $this->brand = $brand;
        $this->color = $color;
        $this->cpu   = $cpu;
        $this->workState = $workState;
        $this->memory = $memory;
        $this->hardDisk = $hardDisk;
        $this->price = $price;
    }

}

$hardDiskDrive = new HardDiskDrive('希捷', 'silver', 'tencent', 'well', '1T', 'hard', '$456');

foreach ($hardDiskDrive as $property => $value) {

    var_dump($property, $value);
    echo '<br>';
}

輸出結果為:

string(5) "brand" string(6) "希捷" 
string(5) "color" string(6) "silver" 
string(3) "cpu" string(7) "tencent" 
string(9) "workState" string(4) "well"

如果我們想遍歷出對象的所有屬性,就需要控制foreach的行為,就需要給類對象,提供更多的功能,需要繼承自Iterator的接口:

該接口,實現了foreach需要的每個操作。foreach的執行流程如下圖:

PHP面向對象特性有哪些

看圖例中,foreach中有幾個關鍵步驟:5個。

而Iterator迭代器中所要求的實現的5個方法,就是用來幫助foreach,實現在遍歷對象時的5個關鍵步驟:

當foreach去遍歷對象時, 如果發現對象實現了Ierator接口, 則執行以上5個步驟時, 不是foreach的默認行為, 而是調用對象的對應方法即可:

PHP面向對象特性有哪些

示例代碼:

class Team implements Iterator {

    //private $name = 'itbsl';
    //private $age  = 25;
    //private $hobby = 'fishing';

    private $info = ['itbsl', 25, 'fishing'];

    public function rewind()
    {
        reset($this->info); //重置數組指針
    }

    public function valid()
    {
        //如果為null,表示沒有元素,返回false
        //如果不為null,返回true

        return !is_null(key($this->info));
    }

    public function current()
    {
        return current($this->info);
    }

    public function key()
    {
        return key($this->info);
    }

    public function next()
    {
        return next($this->info);
    }

}

$team = new Team();

foreach ($team as $property => $value) {

    var_dump($property, $value);
    echo '<br>';
}

PHP內置標準類

如果我們希望把一些數據,以對象的屬性的方式存儲,同時我們又不想定義一個類,可以考慮使用PHP內置標準類stdClass[standard標準]

基本用法:

//注意: stdClass()不是我們自定義的類,而是PHP內置的
$person = new stdClass();

然后我們就可以直接用$person->屬性的方式來使用,屬性都不是系統的,我們自己也沒定義,但是當我們使用這個屬性的時候,系統發現沒有定義就會調用重載方法,重載這個屬性。自動幫我們創建這個屬性。

其它數據類型轉成對象

如果,我們希望把非對象類型轉換成對象,可以通過如下方法實現,(object)來強制轉換,把這些數據轉換成標準內置類stdClass,此種轉換不改變原有數據類型

以上是PHP面向對象特性有哪些的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女