魔術方法 (Magic Methods)
魔術方法是在類別中具有特殊名稱的方法,它們在特定的時機被自動呼叫,這些時機通常與類別的操作和生命週期相關。一個常用的魔術方法是建構子(Constructor)。
建構子 (Constructor)
建構子是一個特殊的方法,它在類別被實例化(物件被建立)時自動被呼叫。建構子通常用於初始化物件的屬性或進行一些初始設定。
class MyClass {
public function __construct() {
echo "物件已被建立!";
}
}
$object = new MyClass(); // 輸出:物件已被建立!
Custom Methods
自訂方法是我們根據類別的需求自行定義的方法。其中的一個常見技巧是使用 return $this
,這使得方法可以被鏈式呼叫(Method Chaining)。
鏈式呼叫(Method Chaining) 指在同一個物件上連續呼叫多個方法,而不需要每次呼叫都賦值給一個變數。
class Calculator {
private $result = 0;
public function add($value) {
$this->result += $value;
return $this; // 返回物件本身以便鏈式呼叫
}
public function subtract($value) {
$this->result -= $value;
return $this; // 返回物件本身
}
public function getResult() {
return $this->result;
}
}
$calculator = new Calculator();
$result = $calculator->add(10)->subtract(5)->getResult();
echo $result; // 輸出:5
在這個例子中,add
和 subtract
方法返回了物件本身 $this
,這樣它們可以連續呼叫,而不需要每次呼叫都賦值給一個變數。
建構子引數的推廣 (Constructor Property Promotion)
在 PHP 8.0 及以上版本中,引入的新特性。
當使用建構子引數推廣之前,我們需要手動為每個類別的屬性指定建構子引數,然後在建構子中賦值。以下是一個使用前的範例:
class User {
private string $name;
private string $email;
private ?string $phoneNumber;
public function __construct(string $name, string $email, ?string $phoneNumber) {
$this->name = $name;
$this->email = $email;
$this->phoneNumber = $phoneNumber;
}
}
// 建立使用者物件
$user = new User('John Doe', 'john@example.com', '123-456-7890');
在上面的範例中,我們需要手動宣告建構子的引數,然後再將這些引數賦值給類別的屬性。
使用建構子引數推廣後的範例:
class User {
public function __construct(
private string $name,
private string $email,
private ?string $phoneNumber = null
) {
// 建構子的內容
}
}
// 建立使用者物件
$user = new User('John Doe', 'john@example.com', '123-456-7890');
在這個例子中,建構子的引數列表直接宣告瞭類別的屬性。$name
和 $email
屬性是必須的,而 $phoneNumber
屬性是可選的(使用 ?string
表示可以為空)。在建構子中,不需要再手動賦值給這些屬性,PHP 會自動處理。這樣,我們可以簡化建構子的定義,使程式碼更加簡潔和易讀。
存取修飾符 (Access Modifiers)
public(公共)
public
修飾符表示該成員(屬性或方法)在類別內外部均可被訪問。這意味著無論是在類別內部、子類別、還是外部程式碼中,都可以直接訪問這個成員,它是預設值。
class MyClass {
public $publicProperty;
public function publicMethod() {
// 可以被任何地方訪問
}
}
protected (受保護)
protected
修飾符表示該成員只能在定義它的類別內部
和子類別
中被訪問。外部程式碼無法直接訪問受保護的成員。
class MyClass {
protected $protectedProperty;
protected function protectedMethod() {
// 只能在類別內部和子類別中訪問
}
}
private(私有)
private
修飾符表示該成員指能在定義它的類別內部
被訪問,對於外部程式碼和子類別都是不可見的。
class MyClass {
private $privateProperty;
private function privateMethod() {
// 只能在類別內部訪問
}
}
Null-Safe Operator
在 PHP 8.0
版本中,引入了 Null-Safe Operator(空安全運算子),也稱為 Null-Safe Operator(?->
),它是一種簡化程式碼的語法糖,用於在操作可能為 null 的物件時避免產生錯誤。
在舊版本的 PHP 中,如果你試圖在一個可能為 null 的變數上呼叫方法或訪問屬性,你必須先檢查該變數是否為 null,以避免產生 Fatal Error。例如:
if (isset($object)) {
$value = $object->getValue();
} else {
$value = null;
}
使用 Null-Safe Operator,你可以將上面的程式碼簡化為:
$value = $object?->getValue();
這樣,如果$object
為 null,表示式的結果將會是 null,而不會丟擲錯誤。Null-Safe Operator 只能用於物件的方法呼叫和屬性訪問,不能用於陣列和函式呼叫
。這個語法糖使得處理可能為 null 的物件更加方便和簡潔。
這裡是一個使用 Null-Safe Operator 的例子:
class MyClass {
public function getValue(): ?string {
// 返回一個可能為null的值
return "Hello, World!";
}
}
$object = null; // 或者一個MyClass的實例
// 使用Null-Safe Operator呼叫可能為null的物件方法
$value = $object?->getValue();
echo $value; // 輸出 "Hello, World!" 或者 null(如果$object為null的話)
在這個例子中,無論$object
是一個 MyClass 的實例還是 null,都不會產生錯誤,因為 Null-Safe Operator 會自動處理 null 情況。
Namespace
在 PHP 中,名稱空間(Namespace)是一種用來解決在不同類別之間命名衝突的機制。名稱空間可以是可選的,但在大型應用程式中,良好的組織和結構是非常重要的。以下是有關 PHP 名稱空間的一些基本概念和最佳實踐:
在程式檔案的最前面,你可以使用namespace
宣告定義一個名稱空間。例如:
declare(strict_types=1);
namespace APP; // after strict_types
class MyClass {
// class implementation
}
如果你的應用程式需要更深的組織結構,你可以使用巢狀名稱空間(Nested Namespace)。例如,如果你有一個銀行相關的類別,你可以這樣定義:
namespace APP\Bank;
class BankAccount {
// class implementation
}
當你在不同的名稱空間中使用類別時,你可以使用use
關鍵字。例如,如果你要使用APP
名稱空間中的Account
類別,你可以這樣做:
# method1
$myAccount = new App\Account();
# method2
use APP\Account;
$myAccount = new Account();
在某些情況下(當前在 namespace APP 下),你可能需要使用 global namespace 中的類別。你可以使用斜線(\)字首來表示全域性名稱空間。例如:
namespace App;
# method1
new \DateTime();
# method2
use DateTime;
new DateTime();
有時候,你可能會想要為一個長命名的類別使用別名(Alias)。這樣可以使你的程式碼更簡潔易讀。例如:
use DateTime as DT;
new DT();
如果你需要引入多個名稱空間中的類別,你可以使用逗號(,)分隔它們。例如:
use APP\Account;
use APP\SocialMedia;
// 改寫
use APP\{Account, SocialMedia};
使用名稱空間和use
語句,讓你可以更好地組織你的程式碼,避免命名衝突,使程式碼更易於維護和擴充套件。
Autoloading Classes
使用自動載入機制(例如 spl_autoload_register
函式)主要是為了方便管理多個類別,特別是當每個類別都儲存在獨立的檔案中時。這樣,你可以根據類別的名稱空間
和類別名稱
來自動載入相應的檔案。
然而,如果在同一個檔案中既有類別定義又有函式定義,那麼最好還是在需要的時候手動引入這些檔案。這是因為自動載入機制主要是為了類別而設計的,而不是用來處理函式。如果在自動載入的過程中引入了一個檔案,裡面除了類別定義還包含其他程式碼(如函式定義),可能會導致不必要的程式碼複雜性和不易讀懂的程式碼。
因此,最佳的做法是:
-
將每個類別儲存在獨立的檔案中。 這樣可以使用自動載入機制,方便地根據類別的名稱空間和類別名稱來自動載入相應的檔案。
-
如果檔案中既有類別定義又有函式定義,需要時手動引入。 如果檔案中有其他不屬於類別的程式碼(例如函式或常數),最好在需要使用這些程式碼的地方手動引入相應的檔案。這樣可以確保程式碼的可讀性和可維護性。
以下是一個範例,演示瞭如何使用自動載入機制來載入類別,並在需要的時候手動引入檔案中的函式:
// require_once 'APP/Account.php';
// require_once 'APP/SocialMedia.php';
// require_once 'APP/..';
spl_autoload_register(function($class){
$formattedClass = str_replace("\\", "/", $class);
$path = "{$formattedClass}.php";
require_once $path;
});
// 使用自動載入機制載入類別
$account = new \APP\Account();
// 手動引入檔案中的函式
require_once 'path/to/file-with-functions.php';
// 現在你可以使用檔案中定義的函式
myFunction();
常數 (Constants)
在 PHP 中,常數是在類別中定義的不可改變的值,這些值在整個類別中都是固定的。在類別中定義常數使用 const
關鍵字,不可使用 define()
函式。
class Account {
const INTEREST_RATE = 0.05;
// 其他類別成員和方法
}
// 存取常數的方式
echo Account::INTEREST_RATE;
在這個範例中,INTEREST_RATE
是 Account
類別的常數,它的值不可更改,可以在整個應用程式中使用,提高了程式碼的可讀性和一致性。
靜態成員 (Static Members)
靜態屬性 (Static Properties)
靜態屬性是指在整個類別中共用的屬性,可以被所有實例共享。然而,靜態屬性的值可以被修改,因此在使用時需要小心 (能不要用就不要用)。
class Account {
public static $count = 0;
public function __construct() {
self::$count++;
}
public static function getCount() {
return self::$count;
}
}
// 使用靜態屬性
$account1 = new Account();
$account2 = new Account();
echo Account::$count; // 輸出:2
在這個例子中,$count
是一個靜態屬性,用來記錄 Account
類別的實例數量。每次建立一個新的 Account
物件時,$count
的值會自動增加。
靜態方法 (Static Methods)
靜態方法是可以在不建立類別實例的情況下直接呼叫的方法。靜態方法通常用於 utility 類別,這些方法不依賴於特定的實例,而是執行通用的任務。這搭配上前面提到的 Autoloading Class
方法時會相當方便。
class Utility {
public static function calculateArea($radius) {
return pi() * $radius * $radius;
}
}
// 呼叫靜態方法
$area = Utility::calculateArea(5); // 計算半徑為5的圓面積
在這個例子中,calculateArea
是一個靜態方法,可以直接透過 Utility::calculateArea()
的方式呼叫,而不需要建立 Utility
物件。