PHP 中的多載(Overloading)

sharkHead 程式技術 5個月前 • 0

PHP 中的多載(overloading)跟其他語言的多載不太一樣
但我本身是菜雞工程師,其他程式的多載我沒有概念
只能說過我碰最深的(雖然還是淺),也就是 PHP

根據官網的說法,PHP 的“多載”目的在於

動態創建類(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)

 

參考資料
Overloading - Manual - PHP
逐步提昇PHP技術能力 - PHP的語言特性 : 多載 (overloading)
 


Laravel 與 Python 菜雞工程師
喜愛研究程式相關技術
正在學習 TypeScript 與 Vue.js