PHP強(qiáng)化之20 - 魔術(shù)方法

魔術(shù)方法是PHP面向?qū)ο笾刑赜械奶匦浴K鼈冊(cè)谔囟ǖ那闆r下被觸發(fā),都是以雙下劃線開頭,你可以把它們理解為鉤子,利用魔術(shù)方法可以輕松實(shí)現(xiàn)PHP面向?qū)ο笾兄剌d(Overloading即動(dòng)態(tài)創(chuàng)建類屬性和方法)。

魔術(shù)方法很多還是成對(duì)出現(xiàn)的,以下列出目前PHP中所有的魔術(shù)方法:

1、__construct()與__destruct

__construct(),類的構(gòu)造函數(shù)。在使用 new關(guān)鍵字使用類實(shí)例化一個(gè)對(duì)象時(shí)自動(dòng)執(zhí)行。

__destruct(),類的析構(gòu)函數(shù)。在對(duì)象被銷毀(unset或PHP執(zhí)行結(jié)束)時(shí)自動(dòng)執(zhí)行,通常用于釋放對(duì)象占用的第三方資源(如:數(shù)據(jù)庫(kù))。

2、__call()與__callStatic()

__call(),在對(duì)象中調(diào)用一個(gè)不可訪問方法時(shí)調(diào)用。

class Person{
  function __call($funName, $arguments)
  { 
     echo "你所調(diào)用的函數(shù):" . $funName . "不存在。\n\r" ; // 輸出調(diào)用不存在的方法名
     echo "參數(shù)為:\n\r";
     print_r($arguments); // 輸出調(diào)用不存在的方法時(shí)的參數(shù)列表           
  }                     
}
$Person = new Person();      
$Person->eat("小明", "蘋果");

以上例程會(huì)輸出:

你所調(diào)用的函數(shù):eat不存在。
參數(shù)為:
Array
(
    [0] => 小明
    [1] => 蘋果
)

__callStatic(),用靜態(tài)方式中調(diào)用一個(gè)不可訪問方法時(shí)調(diào)用。

public static function __callStatic($funName, $arguments){
  //...
}

3、__get()與__set()

當(dāng)對(duì)一個(gè)對(duì)象的未定義的屬性,進(jìn)行“取值”時(shí),此時(shí)會(huì)自動(dòng)調(diào)用類中預(yù)先定義好的魔術(shù)方法__get()。

class Person{
  private $name;
  private $age;
  function __construct($name="", $age=1){
    $this->name = $name;
    $this->age = $age;
  }
  public function __get($propertyName){  
      return $this->$propertyName;
  }
}

$Person = new Person("小明",  50);  
echo "姓名:" . $Person->name . "\n\r"; 
echo "年齡:" . $Person->age . "\n\r";  

以上例程會(huì)輸出:

姓名:小明
年齡:50

__set(),當(dāng)對(duì)一個(gè)對(duì)象的未定義的屬性,進(jìn)行“賦值”時(shí),此時(shí)會(huì)自動(dòng)調(diào)用類中預(yù)先定義好的魔術(shù)方法__set()。

class Person{
  private $name;
  private $age;
 
  public function __set($property, $value) {
    if ($property=="age"){
      if ($value > 150 || $value < 0) {
        return;
      }
    }
    $this->$property = $value;
  }
}
 
$Person=new Person(); 
$Person->name = "小紅";   //賦值成功。如果沒有__set(),則出錯(cuò)。
$Person->age = 16; //賦值成功
$Person->age = 160; //160是一個(gè)非法值,賦值失效

4、__isset()與__unset()

__isset(),當(dāng)對(duì)不可訪問屬性調(diào)用isset()或empty()時(shí)調(diào)用。

__unset(),當(dāng)對(duì)不可訪問屬性調(diào)用unset()時(shí)被調(diào)用。

5、__sleep() 和 __wakeup()

__sleep(),執(zhí)行serialize()時(shí),先會(huì)調(diào)用這個(gè)函數(shù);__wakeup(),執(zhí)行unserialize()時(shí),先會(huì)調(diào)用這個(gè)函數(shù)。

__sleep() 方法常用于提交未提交的數(shù)據(jù),或類似的清理操作。同時(shí),如果有一些很大的對(duì)象,但不需要全部保存,這個(gè)功能就很好用。
__wakeup() 經(jīng)常用在反序列化操作中,例如重新建立數(shù)據(jù)庫(kù)連接,或執(zhí)行其它初始化操作。

class Person{
  public $sex;
  public $name;
  public $age;

  public function __construct($name="", $age=25, $sex='男'){
    $this->name = $name;
    $this->age = $age;
    $this->sex = $sex;
  }
  
  public function __sleep() {
    echo "當(dāng)在類外部使用serialize()時(shí)會(huì)調(diào)用這里的__sleep()方法<br>";
    $this->name = base64_encode($this->name);
    return array('name', 'age'); // 這里必須返回一個(gè)數(shù)值,里邊的元素表示返回的屬
性名稱
  }
  
  public function __wakeup() {
    echo "當(dāng)在類外部使用unserialize()時(shí)會(huì)調(diào)用這里的__wakeup()方法<br>";
    $this->age = 30;
    $this->sex = '女';
    // 這里不需要返回?cái)?shù)組
  }
}
 
$person = new Person('小明'); // 初始賦值
$a = serialize($person);
var_dump($a);
$b = unserialize($a);
var_dump($b);

以上例程會(huì)輸出:

當(dāng)在類外部使用serialize()時(shí)會(huì)調(diào)用這里的__sleep()方法
/var/www/html/demo28.php:29:string 'O:6:"Person":2:{s:4:"name";s:8:"5bCP5piO";s:3:"age";i:25;}' (length=58)
當(dāng)在類外部使用unserialize()時(shí)會(huì)調(diào)用這里的__wakeup()方法
/var/www/html/demo28.php:31:
object(Person)[2]
  public 'sex' => string '女' (length=3)
  public 'name' => string '5bCP5piO' (length=8)
  public 'age' => int 30

官方例子:

class Connection {
    protected $link;
    private $server, $username, $password, $db;
    
    public function __construct($server, $username, $password, $db) {
        $this->server = $server;
        $this->username = $username;
        $this->password = $password;
        $this->db = $db;
        $this->connect();
    }
    
    private function connect() {
        $this->link = mysql_connect($this->server, $this->username, $this->password);
        mysql_select_db($this->db, $this->link);
    }
    
    public function __sleep(){
        return array('server', 'username', 'password', 'db');
    }
    
    public function __wakeup(){
        $this->connect();
    }
}

6、__toString()

__toString() 方法用于一個(gè)類被當(dāng)成字符串時(shí)應(yīng)怎樣回應(yīng)。

例如 echo $obj; 應(yīng)該顯示些什么。此方法必須返回一個(gè)字符串,否則將發(fā)出一條 E_RECOVERABLE_ERROR 級(jí)別的致命錯(cuò)誤。

class TestClass{
    public $foo = __CLASS__;

    public function __toString() {
        return $this->foo;
    }
}

$class = new TestClass();
echo $class;

以上例程會(huì)輸出:

TestClass

7、__invoke()

當(dāng)嘗試以調(diào)用函數(shù)的方式調(diào)用一個(gè)對(duì)象時(shí),__invoke() 方法會(huì)被自動(dòng)調(diào)用。

class CallableClass {
    function __invoke($x) {
        var_dump($x);
    }
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));

以上例程會(huì)輸出:

int(5)
bool(true)

8、__set_state()

__set_state(),調(diào)用var_export()導(dǎo)出類時(shí),此靜態(tài)方法會(huì)被調(diào)用。

class A{
    public $var1;
    public $var2;

    public static function __set_state($an_array){
        $obj = new A;
        $obj->var1 = $an_array['var1'];
        $obj->var2 = $an_array['var2'];
        return $obj;
    }
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';

eval('$b = ' . var_export($a, true) . ';'); // $b = A::__set_state(array(
                                            //    'var1' => 5,
                                            //    'var2' => 'foo',
                                            // ));
var_dump($b);

以上例程會(huì)輸出:

object(A)#2 (2) {
  ["var1"]=>
  int(5)
  ["var2"]=>
  string(3) "foo"
}

9、__clone()

在克?。╟lone)對(duì)象時(shí)自動(dòng)執(zhí)行。

class C {
    public function __clone() {
        echo '正在克隆。。。';
    }
}

$a = new C();
$b = clone $a;

以上例程會(huì)輸出:

正在克隆。。。

10、__autoload()

__autoload(),嘗試加載未定義的類。

function __autoload($className) { 
  $filePath = "project/class/{$className}.php"; 
  if (is_readable($filePath)) { 
    require($filePath); 
  } 
} 

隨著PHP版本的更新,該函數(shù)已經(jīng)不建議使用,取而代之的是spl_auto_register()函數(shù)。

11、__debugInfo()

__debugInfo(),打印所需調(diào)試信息。

class C {
    private $prop = 'test';
    
    public function __debugInfo() {
        return [
            'data1' => $this->prop,
        ];
    }
}

var_dump(new C());

以上例程會(huì)輸出:

class C#1 (1) {
  public $data1 =>
  string(4) "test"
}

官方文檔:http://php.net/manual/zh/language.oop5.magic.php

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容