Miles' Blog

天涯何處無幹話,何必要講實務話

Magic Method

一般 PHP 的教學書都會這麼建議:

  • public method的名稱直接打,如 public function getData() {}
  • private 或 protected method的名稱前面加一個底線,如 protected function _getData() {}
  • 另外最好不要用兩個底線開頭,如 private function __getData() {}

其實是因為 PHP 把所謂的 Magic Method 名稱都是設定為兩個底線開頭的。Magic Method 正如其名,用起來會讓開發者覺得很 Magic,活用它的特性還能讓其他開發者覺得 Amazing!

PHP 其實已經有預設好幾個名稱,開發者其實也只要了解什麼時候會去調用它就行了。

__construct()

void __construct ([ mixed $args [, $... ]] )

這是 PHP 開發者最常使用的 Magic Method 了,這個 method 被 call 的時機是在建構的時候:

$obj = new ClassName(); 

在 new 的同時,ClassName::__construct() 就會先執行了。通常這個 Magic Method 都是用在物件初始化。而方法後面所設定的參數要在 new 的後面傳入,如:

class ClassName {
public __construct ($data, $default = true){}
}

$obj = new ClassName($data);

另外,__construct 的能見度如果是 public 的話,代表這是可以被外部實例化的類別;相反的,如果是 privateprotected 的話,就不能被外部實例化,但可以從內部的靜態方法裡實作實例化的方法。

__destruct()

void __destruct ( void )

這個就比較不常見了,它在解構的時候會執行,除了程式結束外,就是 unset 的時候了:

unset($obj);

通常是用在程式收尾,如資料庫斷線等。

__call()

public mixed __call ( string $name , array $arguments )

這個就比較神奇了!

今天宣告一個 class 如下:

class ClassName {
public __call ($name, $arg) {
echo 'No ' . $name . ' Method.';
}
}

當我實例化並呼叫不存在方法(或非公開方法)時,就會呼叫 __call 方法了:

$obj = new ClassName();
$obj->getData() // Output: "No getData Method."

參考下面程式碼

class User {
public findUser($condition) {
// Get user data by condition.
return $data;
}

public __call ($name, $arg) {
if (strpos('findUserBy', $name) == 0) {
$condition = strtolower(substr($name, 10));
return findUser($condition);
}
}
}

$obj = new User();
$userdata = $obj->findUser('id');
$userdata = $obj->findUserById();

後面兩個寫法的結果會是一樣的,所以代表可以有理論無限多個 Method。只是 Exception 要做好才不會有問題產生。

__callStatic()

public static mixed __callStatic ( string $name , array $arguments )

原理跟 __call() 一樣,不過是 static 的。

__get()

public mixed __get ( string $name )

__call() 很像,不過這是當要取得未定義或非公開的屬性時會呼叫的方法。如:

$data = $obj->data;  // $obj->data  is not define / not public.

以上例來說,$name 的值為 ‘’data’’。

__set()

public void __set ( string $name , mixed $value )

__get(),設值一個未定義或非公開屬性時會呼叫的方法。

$obj->data = ‘John’; // $obj->data is not define / not public.

以上例來說,$name 的值為 data$value 的值為 John

__isset()

public bool __isset ( string $name )

當對未定義或非公開屬性使用 isset()empty() 時,會被呼叫。

isset($obj->data);

__unset()

public void __unset ( string $name )

當對未定義或非公開屬性使用 unset() 時會被呼叫。

unset($obj->data);

__toString()

public string __toString ( void )

當想要把物件當作一個 string 時,就會呼叫這個 Magic Method 並回傳一個值,如:

class User
{
public function __toString()
{
echo 'User';
}
}

$obj = new User();
echo $obj; // Output: User

比較實際的應用如: JSON 物件處理完成後,要輸出時,就可以直接把物件當作字串輸出即可。

__invoke()

mixed __invoke ([ $... ] )

當想要把物件當作一個 function 呼叫時,就會呼叫這個 Magic Method,如(官方範例):

class CallableClass 
{
function __invoke($x) {
var_dump($x);
}
}

$obj = new CallableClass();
$obj(5);

var_dump(is_callable($obj));

Reference

0%