1. 程式人生 > 實用技巧 >PHP面向物件程式設計(一)

PHP面向物件程式設計(一)

PHP類與物件、訪問控制

概述

面向物件程式設計(OOP)是一種計算機程式設計架構,和基於函式構建程式不同,面向物件程式設計的思想是在程式中包含各種獨立而又相互呼叫的物件,每一個物件都能夠接受資料、處理資料(物件方法實現)、並將資料表達給其他物件,當我們下達指令時,不再是呼叫函式,而是指定物件的方法。因此,在面向物件程式設計中,物件是程式的基本單元,一個物件包含了資料和操作資料的函式。

面向物件的中最核心的概念就是類(Class)和物件(Object),類是物件的抽象模板,而物件是類的具體例項。

編寫自定義類

以汽車為例編寫一個自定義類Car

<?php
class Car
{

}

類通過關鍵字class進行宣告,然後緊跟類名Car(通常以大寫字母開頭定義類名)

//通過php內建class_exists方法判斷該類是否存在
if (class_exists('Car')) {
    echo 'Car存在';
}else{
    echo 'Car不存在';
}

類屬性

類屬性可以是變數,也可以是常量。

<?php

class Car
{
    const WHEELS = 4; //汽車都是4個輪子
    var $seats; //座位
    var $doors; //門
    var $engine; //發動機
    var $brand; //品牌
}

通過var來定義變數屬性,通過const來定義常量屬性(常量大寫無$字首)

類方法

<?php

class Car
{
    const WHEELS = 4; //汽車都是4個輪子
    var $seats; //座位
    var $doors; //門
    var $engine; //發動機
    var $brand; //品牌

    /**
     * @return mixed
     */
    public function getBrand()
    {
        return $this->brand;
    }

    /**
     * @param mixed $brand
     */
    public function setBrand($brand)
    {
        $this->brand = $brand;
    }

    /**
     * 開車
     */
    public function drive()
    {
        echo "1.啟動引擎..." . PHP_EOL;
        echo "2.掛D檔..." . PHP_EOL;
        echo "3.放下手剎..." . PHP_EOL;
        echo "4.踩油門,出發..." . PHP_EOL;
    }

    /**
     * 熄火
     */
    public function close()
    {
        echo "1.踩剎車..." . PHP_EOL;
        echo "2.掛P檔..." . PHP_EOL;
        echo "3.拉起手剎..." . PHP_EOL;
        echo "4.關閉引擎..." . PHP_EOL;
    }

}

例項化物件

通過new關鍵字進行類的例項化

$car = new Car();

類常量是類級別的,無需例項化即可訪問,類常量不能更改只能訪問,在類外面訪問常量,需要通過類名+::+常量名稱的方式:

var_dump(Car::WHEELS);

物件級別的類屬性(變數型別),需要例項化物件才能訪問。

//修改類屬性
$car->seats = 5;
//訪問類屬性
var_dump($car->seats);

訪問類方法 通過物件例項+->+物件名即可

$car->drive();

建構函式

上述物件例項化是通過new Car()來實現的,這段程式碼實際上呼叫了Car的預設建構函式,建構函式的用途是在物件例項化過程中呼叫,用於對物件的一些初始化操作。

/**
     * Car constructor.
     * @param $seats
     * @param $doors
     * @param $engine
     * @param $brand
     */
    public function __construct($seats, $doors, $engine, $brand)
    {
        $this->seats = $seats;
        $this->doors = $doors;
        $this->engine = $engine;
        $this->brand = $brand;
    }

訪問控制

PHP通過public(公開)、protected(保護)、private(私有)關鍵字控制類屬性和方法的可見性:

  • 對於通過public宣告的屬性和方法,在類以外和繼承類中均可見;
  • 對於通過protected宣告的屬性和方法,在繼承類(支援多層級)中可見,類以外不可見;
  • 對於private宣告的屬性和方法,僅在當前類內部可見,在繼承類和類以外不可見

所謂的「可見」與「不可見」,是一種形象的說法,實際含義是可訪問可設定。我們前面定義的類方法都是通過 PhpStorm 自帶模版生成的,預設都是 public 宣告,對於建構函式來說,除了單例模式這種特殊場景,其他都是需要通過 public 宣告,否則在類以外不可見影響物件例項化。對於操作屬性的 Getters/Setters 方法通常用於從外部處理 private 型別屬性,所以也需要宣告為 public,其他的場景可以根據具體業務場景需求來。

我們之前通過 var 宣告類屬性,這是比較老的用法,是為了向後相容 PHP 4,在 PHP 5 中,通過 var 宣告的屬性和方法統統被視作 public,所以我們在測試程式碼中可以從外部直接訪問和設定,下面,我們將其都設定為 protected 型別,以便在當前類和繼承類中可見,在類以外不可見,從而保護對應屬性不被惡意修改:

protected $seats;         // 座位
protected $doors;         // 門
protected $engine;        // 發動機
protected $brand;         // 品牌

面向物件三個特性 :繼承、封裝、多型

繼承

PHP遵循單繼承機制,即一個子類只能繼承一個父類。

所謂繼承,指的是子類可以通過繼承的方式訪問父類的屬性和方法(protected或者public方式定義),在php中,整合通過extends關鍵字實現。

class Benz extends Car
{
    public function __construct($seats=5, $doors=4, $engine=1)
    {
        $this->brand = '賓士';
        parent::__construct($seats, $doors, $engine, $this->brand);
    }
}

extends Car的含義就是Benz繼承自Car,是他的子類,相對的,Car是Benz父類。

子類呼叫父類的同名方法需要通過parent::進行呼叫。

封裝

概念

封裝一方面指的是呼叫者無需關心物件實現細節,另一方面是通過訪問控制限定屬性和方法的可見性。

反射

可以通過反射的方式呼叫類的私有方法。

class Benz extends Car
{
    private $customProp = '自定義屬性';
    public function __construct($seats=5, $doors=4, $engine=1)
    {
        $this->brand = '賓士';
        parent::__construct($seats, $doors, $engine, $this->brand);
    }

    private function customMethod()
    {
        echo "Call custom prop \$customProp: " . $this->customProp . PHP_EOL;
    }

}


//通過反射呼叫私有方法
$method = new ReflectionMethod(Benz::class,'customMethod');
設定方法是否可執行
$method->setAccessible(true);

$benz = new Benz();
//執行一個反射方法
$method->invoke($benz);

多型

方法重寫

所謂多型,指的是PHP繼承體系中,子類可以重寫父類同名方法。

型別轉化

當類作為引數型別宣告時,如果宣告型別為父類,則可以傳入子類物件,反過來,如果宣告型別為子類,則不能傳入父類物件。

PHP抽象類與介面

抽象類

抽象類指的是包含抽象方法的類,而抽象方法是通過abstract關鍵詞修飾的方法,抽象方法只是一個方法,不能有具體實現:

abstract public function drive();

只要是某個類包含了至少一個抽象方法,他就是抽象類,抽象類也需要通過abstract關鍵詞修飾。

<?php
abstract class Car
{
    abstract public function drive();
}

抽象類本身不能被例項化,只能被子類繼承,繼承了抽象類的子類必須實現父類的抽象方法。

介面

介面通過interface關鍵字宣告,介面中可以定義多個方法宣告,這些方法宣告不能有任何實現,並且這些方法的可見性都應該是public,因為介面中的方法都要被其他類實現。

<?php
interface Car
{
	public function drive();
}

標識一個類實現了某個介面通過關鍵字implements完成。

<?php

interface Car
{
    public function drive();
}

class LynkCo01 implements Car
{
    protected $brand;

    public function __construct($brand)
    {
        $this->brand = $brand;
    }

    public function drive()
    {
        echo "啟動{$this->brand}汽車" . PHP_EOL;
    }
}

型別運算子 instanceof

instanceof,用於判斷某個物件例項是否實現了某個介面,或者是某個父類/抽象類的子類例項