PHP 類和物件

在本教程中,你將學習如何在 PHP 中以物件導向的方式編寫程式碼。

什麼是物件導向的程式設計

物件導向程式設計(OOP)是一種基於類和物件概念的程式設計模型。與過程程式設計相反,其中重點在於編寫對資料執行操作的過程或函式,在物件導向的程式設計中,重點在於包含資料和函式的物件的建立。

與傳統或程式式程式設計相比,物件導向程式設計具有幾個優點。最重要的列表如下:

  • 它為程式提供了清晰的模組化結構。
  • 它可以幫助你遵循“不要重複自己”(Don’t Repeat Yourself - DRY)原則,從而使你的程式碼更易於維護,修改和除錯。
  • 它可以用更少的程式碼和更短的開發時間以及高度的可重用性來建立更復雜的行為。

以下部分將描述類和物件在 PHP 中的工作方式。

提示:過程程式設計風格編寫的程式,意味著程式由一個或多個過程組成。然而,過程是一組程式設計語句,它們一起執行特定任務。

提示: 不要重複自己(DRY)原則背後的想法是通過抽象出應用程式常用的程式碼並將它們放在一個地方並重用它們而不是重複它來減少程式碼的重複。

理解類和物件

類和物件是物件導向程式設計的兩個主要方面。類是一個獨立的,獨立的變數和函式集合,它們協同工作以執行一個或多個特定任務,而物件是類的單個例項。

類充當模板或藍圖,可以從中建立許多單個物件。建立單個物件時,它們會繼承相同的通用屬性和行為,儘管每個物件對於某些屬性可能具有不同的值。

例如,將一個類視為房屋的藍圖。藍圖本身不是房子,而是房子的詳細計劃。然而,一個物體就像是根據該藍圖建造的實際房屋。我們可以用相同的藍圖建造幾個相同的房子,但每個房子裡面可能有不同的油漆,室內和家庭,如下圖所示。

類物件關係圖

可以使用 class 關鍵字宣告類,後跟類的名稱和一對花括號({}),如以下示例所示。

讓我們建立一個名為 Rectangle.php 的 PHP 檔案,並在其中放入以下示例程式碼,以便我們的類程式碼應該與程式的其餘部分分開。然後我們可以通過簡單地包含 Rectangle.php 檔案在任何需要的地方使用它。

<?php
class Rectangle
{
    // Declare  properties
    public $length = 0;
    public $width = 0;
    
    // Method to get the perimeter
    public function getPerimeter(){
        return (2 * ($this->length + $this->width));
    }
    
    // Method to get the area
    public function getArea(){
        return ($this->length * $this->width);
    }
}
?>

public 關鍵字在上面的例子中的屬性和方法之前,是一個訪問修飾符,其指示該屬性或方法是從任何地方訪問。我們將在本章後面稍後詳細瞭解這一點。

注意:從語法上講,類中的變數稱為屬性,而函式稱為方法。此外,類名通常用 PascalCase 編寫,即每個連線的單詞以大寫字母開頭(例如 MyClass)。

定義類後,可以使用 new 關鍵字從類建立物件。可以通過此物件例項直接訪問類方法和屬性。

建立另一個 PHP 檔名 test.php 並將以下程式碼放入其中。

<?php
// Include class definition
require "Rectangle.php";
 
// Create a new object from Rectangle class
$obj = new Rectangle;
 
// Get the object properties values
echo $obj->length; // 0utput: 0
echo $obj->width; // 0utput: 0
 
// Set object properties values
$obj->length = 30;
$obj->width = 20;
 
// Read the object properties values again to show the change
echo $obj->length; // 0utput: 30
echo $obj->width; // 0utput: 20
 
 
// Call the object methods
echo $obj->getPerimeter(); // 0utput: 100
echo $obj->getArea(); // Output: 600
?>

箭頭符號(->)是一個 OOP 結構,用於訪問給定物件的包含屬性和方法。然而,偽變數 $this 提供對呼叫物件的引用,即該方法所屬的物件。

當使用同一類的多個例項時,物件導向程式設計的真正力量變得明顯,如以下示例所示:

<?php
// Include class definition
require "Rectangle.php";
 
// Create multiple objects from the Rectangle class
$obj1 = new Rectangle;
$obj2 = new Rectangle;
 
// Call the methods of both the objects
echo $obj1->getArea(); // Output: 0
echo $obj2->getArea(); // Output: 0
 
// Set $obj1 properties values
$obj1->length = 30;
$obj1->width = 20;
 
// Set $obj2 properties values
$obj2->length = 35;
$obj2->width = 50;
 
// Call the methods of both the objects again
echo $obj1->getArea(); // Output: 600
echo $obj2->getArea(); // Output: 1750
?>

正如你在上面的示例中所看到的, getArea() 在不同物件上呼叫該方法會導致該方法對不同的資料集進行操作。每個物件例項都是完全獨立的,具有自己的屬性和方法,因此可以獨立操作,即使它們屬於同一個類。

使用建構函式和解構函式

為了使物件導向的程式設計更容易,PHP 提供了一些在物件內發生某些操作時自動執行的魔術方法。

例如,無論何時建立新物件,都會自動執行魔術方法 __construct() (稱為建構函式)。類似地,魔術方法 __destruct() (稱為解構函式)在物件被銷燬時自動執行。一旦物件被銷燬,解構函式就會清除分配給物件的所有資源。

<?php
class MyClass
{
    // Constructor
    public function __construct(){
        echo 'The class "' . __CLASS__ . '" was initiated!<br>';
    }
    
    // Destructor
    public function __destruct(){
        echo 'The class "' . __CLASS__ . '" was destroyed.<br>';
    }
}
 
// Create a new object
$obj = new MyClass;
 
// Output a message at the end of the file
echo "The end of the file is reached.";
?>

上例中的 PHP 程式碼將產生以下輸出:

The class "MyClass" was initiated!  

The end of the file is reached.

The class "MyClass" was destroyed. 

指令碼結束時會自動呼叫解構函式。但是,要顯式觸發解構函式,可以使用 PHP unset() 函式銷燬物件,如下所示:

<?php
class MyClass
{
    // Constructor
    public function __construct(){
        echo 'The class "' . __CLASS__ . '" was initiated!<br>';
    }
    
    // Destructor
    public function __destruct(){
    echo 'The class "' . __CLASS__ . '" was destroyed.<br>';
    }
}
 
// Create a new object
$obj = new MyClass;
 
// Destroy the object
unset($obj);
 
// Output a message at the end of the file
echo "The end of the file is reached.";
?>

現在,上面示例中的 PHP 程式碼將生成以下輸出:

  The class "MyClass" was initiated!
  The class "MyClass" was destroyed.
  The end of the file is reached. 

提示: PHP 會在指令碼完成時自動清理執行期間分配的所有資源,例如關閉資料庫連線,銷燬物件等。

注意: __CLASS__ 是一個魔術常量,它包含發生它的類的名稱。如果它發生在類外部,它將會是空的。

通過繼承擴充套件類

類可以使用 extends 關鍵字繼承另一個類的屬性和方法。這個可擴充套件性過程稱為繼承。這可能是使用物件導向程式設計模型背後最有力的原因。

<?php
// Include class definition
require "Rectangle.php";
 
// Define a new class based on an existing class
class Square extends Rectangle
{   
    // Method to test if the rectangle is also a square
    public function isSquare(){
        if($this->length == $this->width){
            return true; // Square
        } else{
            return false; // Not a square
        }
    }
}
 
// Create a new object from Square class
$obj = new Square;
 
// Set object properties values
$obj->length = 20;
$obj->width = 20;
 
// Call the object methods
if($obj->isSquare()){
    echo "The area of the square is ";
} else{
    echo "The area of the rectangle is ";
};
echo $obj->getArea();
?>

上例中的 PHP 程式碼將產生以下輸出:

  The area of the square is 400
 

正如你可以在上面的例子中看到,雖然廣場的類定義不明確包含 getArea() 的方法,也不是 $length$width 財產,Square 類的例項可以使用它們,因為它們從父 Rectangle 類繼承。

提示: 由於子類是從父類派生的,因此它也稱為派生類,其父類稱為基類。

控制屬性和方法的可見性

使用類時,你甚至可以使用可見性關鍵字限制對其屬性和方法的訪問,以實現更好的控制。有三種能見度關鍵字(從最可見的至少可見): , publicprotectedprivate 其確定的屬性和方法的方式和從那裡可以訪問和修改。

  • public - 可以在課堂內外的任何地方訪問公共財產或方法。這是 PHP 中所有類成員的預設可見性。
  • protected - 受保護的屬性或方法只能在類本身內或子類或繼承類(即擴充套件該類的類)中訪問。
  • private - 私有屬性或方法只能在定義它的類中訪問。即使是子類或繼承的類也無法訪問私有屬性或方法。

以下示例將向你展示此可見性實際如何工作:

<?php
// Class definition
class Automobile
{
    // Declare  properties
    public $fuel;
    protected $engine;
    private $transmission;
}
class Car extends Automobile
{
    // Constructor
    public function __construct(){
        echo 'The class "' . __CLASS__ . '" was initiated!<br>';
    }
}
 
// Create an object from Automobile class
$automobile = new Automobile;
 
// Attempt to set $automobile object properties
$automobile->fuel = 'Petrol'; // ok
$automobile->engine = '1500 cc'; // fatal error
$automobile->transmission = 'Manual'; // fatal error
 
// Create an object from Car class
$car = new Car;
 
// Attempt to set $car object properties
$car->fuel = 'Diesel'; // ok
$car->engine = '2200 cc'; // fatal error
$car->transmission = 'Automatic'; // undefined
?>

靜態屬性和方法

除了知名度,屬性和方法,也可以宣告為 static ,這使得他們無需類的例項訪問。可以使用範圍解析運算子(::) 來訪問靜態屬性和方法,如下所示: ClassName::$propertyClassName::method()

宣告為靜態屬性不能經由類,但是一個靜態方法可以是的物件來訪問,如在下面的例子所示:

<?php
// Class definition
class HelloClass
{
    // Declare a static property
    public static $greeting = "Hello World!";
    
    // Declare a static method
    public static function sayHello(){
        echo self::$greeting;
    }
}
// Attempt to access static property and method directly
echo HelloClass::$greeting; // Output: Hello World!
HelloClass::sayHello(); // Output: Hello World!
 
// Attempt to access static property and method via object
$hello = new HelloClass;
echo $hello->greeting; // Strict Warning
$hello->sayHello(); // Output: Hello World!
?>

上例中的關鍵字 self 表示“當前類”。它永遠不會以美元符號($)開頭,並且始終跟隨 :: 運算子(例如 self::$name)。

所述 self 關鍵字是從不同 this ,意思是“當前物件”或“一類的當前例項”關鍵字。的 this 關鍵字總是由一個美元符號前面($)和隨後 -> 操作者(例如 $this->name)。

注意: 由於可以在沒有類例項(即物件)的情況下呼叫靜態方法,因此偽變數 $this 在宣告為 static 的方法中不可用。

我們希望你現在已經理解了物件導向程式設計的基本概念。你將在 PHP 和 MySQL 資料庫部分找到有關 OOP 的更多示例。