PHP 中的多載 (Overloading)
PHP 中的多載 (Overloading) 跟其他語言的多載不太一樣,但我本身是菜雞工程師,其他程式的多載我沒有概念,只能說過我碰最深的 (雖然還是淺) ,也就是 PHP。
根據官網的說法,PHP 的多載 (Overloading) 目的在於動態創建類 (Class) 的屬性 (Property) 還有方法 (Method) 。
方法 (Method) 與函式 (Function) 差在哪裡?這兩個在程式碼中明明都是 function,但為什麼會有方法與函式兩種稱呼呢?
主要差別在,當一個函式放在類別 (Class) 裡面,這個函式就可以稱為方法,反之,當一個函式沒有放在任何類別中,那麼就是一個單純的函式。
PHP 的多載提供幾個魔術方法,分別是。
__set(string $name, mixed $value): void
__get(string $name): mixed
__isset(string $name): bool
__unset(string $name): void
__set()
方法是在賦值給不可訪問的屬性時會觸發,什麼是不可訪問的屬性?
例如原本類別中沒有設定或是設定成 private 的屬性,以下方的 Code 舉例。
<?php
class PropertyTest
{
// 被重載的數據保存在此
public $data = [];
// 只有從類外部訪問這個屬性時,重載才會發生
private $hidden = 2;
public function __set($name, $value)
{
echo '已觸發 __set() 方法,設定 ' . $name . ' 為 ' . $value . PHP_EOL;
$this->data[$name] = $value;
}
}
$obj = new PropertyTest();
// 賦值給 $obj 沒有的屬性
$obj->a = 1;
// 賦值給 $obj 中設定為 private (私有成員) 的屬性
$obj->hidden = 2;
print_r($obj->data);
因為 PropertyTest()
中沒有設定 $a
屬性,而 $hidden
屬性是設定為私有成員,外部無法訪問。
因此嘗試賦值給 $a
與 $hidden
屬性都會觸發 __set()
方法。
上述的程式碼的執行結果為。
已觸發 __set() 方法,設定 a 為 1
已觸發 __set() 方法,設定 hidden 為 2
Array
(
[a] => 1
[hidden] => 2
)
__get()
方法是在讀取不可訪問的屬性時會被觸發。
<?php
class PropertyTest
{
// 重載不能被用在已經定義的屬性
public $declared = '讀取 $declared 這個屬性並不會觸發 __get() 方法';
// 只有從類外部訪問這個屬性時,重載才會发生
private $hidden = 2;
public function __get($name)
{
echo '已觸發 __get() 方法,讀取 ' . $name;
}
}
$obj = new PropertyTest();
echo $obj->declared . PHP_EOL;
echo $obj->a . PHP_EOL;
echo $obj->hidden . PHP_EOL;
上述程式碼的執行結果為。
讀取 $declared 這個屬性並不會觸發 __get() 方法
已觸發 __get() 方法,讀取 a
已觸發 __get() 方法,讀取 hidden
__isset()
與 __unset()
方法跟官網一樣放在一起講,當對不可訪問的屬性調用 isset()
或 empty()
時,__isset()
會被調用,當對不可訪問屬性調用 unset()
時,__unset()
會被調用。
<?php
class PropertyTest
{
// 被重載的數據保存在此
private $data = ['a' => 1];
public function __isset($name)
{
echo $name . ' 有被設定嗎?' . PHP_EOL;
return isset($this->data[$name]);
}
public function __unset($name)
{
echo '將 ' . $name . ' 改成未設定' . PHP_EOL;
unset($this->data[$name]);
}
}
$obj = new PropertyTest;
var_dump(isset($obj->a));
echo PHP_EOL;
unset($obj->a);
echo PHP_EOL;
var_dump(isset($obj->a));
上述程式碼的執行結果為。
a 有被設定嗎?
bool(true)
將 a 改成未設定
a 有被設定嗎?
bool(false)