PHP 中的多載 (Overloading)

程式技術
sharkHead

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)

參考資料

sharkHead
written by
sharkHead

後端打工仔,在下班後喜歡研究各種不同的技術。稍微擅長 PHP,並偶爾涉獵前端開發。個性就像動態語言般隨興,但渴望做事能像囉嗦的靜態語言那樣嚴謹。

0 則留言