PHP中常見的魔術方法

一. __construct(),類的構造函數

PHP中構造函數是一個對象創建完成後第一個被對象自動調用的方法。在每個類中都有一個構造方法,如果沒有顯示的聲明它,那麼類中都會默認存在一個沒有參數且內容爲空的構造方法。

  1. 構造方法的作用
    通常構造方法被用來執行一些有用的初始化任務,如對成員屬性在創建對象時賦予初始值
  2. 例子
<?php
class Person
{ 
 public $name;        
 public $age;
                                                                           
 public function __construct($name="", $age=22)
 {      
        $this->name = $name;
        $this->age = $age;
    }
    
    public function say()
    { 
        echo "我叫:" . $this->name . ",年齡:" . $this->age;
    }                                                                                          
}

$Bob = new Person('Bob');
echo $Bob->say();
//Output: 我叫:Bob,年齡:22

二. __destruct(),類的析構函數

  1. 析構函數的作用
    析構函數允許在銷燬一個類之前執行的一些操作或完成的一些功能。注意:析構函數不能帶有任何參數
  2. 例子
<?php
class Person
{ 
 public $name;        
 public $age;
                                                                           
 public function __construct($name="", $age=22)
 {      
        $this->name = $name;
        $this->age = $age;
    }
    
 public function __destruct()
 {
  echo $this->name."快沒了!";
 }                                                                                          
}
$Bob = new Person('Bob');
unset($Bob);//銷燬$Bob對象
//Output: Bob快沒了!

三. __call(),在對象中調用一個不可訪問方法時調用

該方法有兩個參數,第一個參數爲$function_name會自動接收不存在的方法名,第二個參數$arguments則以數組接收不存在方法的多個參數。

  1. __call()方法的作用
    爲了避免當調用方法不存在時產生錯誤而意外中止程序,可以使用__call()方法來避免。該方法在調用的方法不存在時會自動調用該方法,程序會繼續執行下去。
  2. 例子
<?php
class Person
{ 
    public function say()
    { 
        echo "Hello World!";
    }
    
    function __call($funname,$arguments)
 {
  echo $funname."(參數:";
  print_r($arguments);
  echo ")方法不存在\n";
 }                                                                                          
}

$Bob = new Person();
$Bob->eat("cake");
$Bob->say();
// Output: 
// eat(參數:Array( [0] => cake ))方法不存在
// Hello World!

四. __callStatic(),用靜態方式中調用一個不可訪問方法時調用

  1. __callStatic()方法的作用
    該方法與__call()方法一樣,只不過是調用靜態方法不存在時調用該方法。
  2. 例子
<?php
class Person
{ 
 public function say()
 { 
     echo "Hello World!";
 }
 
 static function __callStatic($funname,$arguments)
 {
  echo $funname."(參數:";
  print_r($arguments);
  echo ")靜態方法不存在\n";
 }                                                                                          
}

$Bob = new Person();
$Bob::eat("cake");
$Bob->say();
// Output: 
// eat(參數:Array( [0] => cake ))靜態方法不存在
// Hello World!

五. __get(),獲得一個類的成員變量時調用

在PHP中,類的成員屬性被設定爲private後,如果我們試圖在外部調用它則會出現"不能訪問某個私有屬性"錯誤。爲了解決這個問題,我們可以使用__get()方法。

  1. __get()方法的作用
    在程序運行過程中,通過它可以在對象的外部獲取私有成員屬性的值。
  2. 例子
<?php
class Person
{ 
 private $name;
 private $age;
 
 function __construct($name,$age)
 { 
     $this->name = $name;
     $this->age = $age;
 }
 
 function __get($name)
 {
  if ($name == 'name'){
   return $this->name;
  } else {
   return $this->age;
  }
 }                                                                                          
}

$Bob = new Person('Bob','18');
echo "name:".$Bob->name." "."age:".$Bob->age;
// Output: name:Bob age:18

六. __set(),設置一個類的成員變量時調用

  1. __set()方法的作用
    __set($property,$value)方法用來設置私有屬性,給一個未定義的屬性賦值時,此方法會被觸發,傳遞的參數是被設置呃屬性名和值。
  2. 例子
<?php
class Person
{ 
 private $name;
 private $age;
 
 function __construct($name,$age)
 { 
     $this->name = $name;
     $this->age = $age;
 }
 
 function __set($name,$value)
 {
  if ($name == 'age'){
   if ($value > 100 || $value <0 ){
    return;
   } 
  }
  $this->$name = $value;
 }
 
 function say(){
  echo "name:".$this->name." "."age:".$this->age;
 }                                                                                         
}

$person = new Person('Bob','18');
$person->name = "Alice"; //如果沒有__set()方法則會報錯
$person->age = 160; //160是個非法值,賦值失敗
$person->say();
$person->age = 16; //賦值成功
$person->say();
// Output:
// name:Alice age:18
// name:Alice age:16

七. __isset(),當對不可訪問屬性調用isset()或empty()時調用

我們首先了解一下isset()函數,檢測變量是否設置,如果設置返回true,否則返回false。

<?php
$a = "1";
if (isset($a)){
 echo "true";
} else {
 echo "false";
}// Output: true

如果在一個對象外面想要使用isset()方法去檢測對象裏面的成員是否可以使用呢?
這裏分爲兩種情況,如果對象的成員是公有的則可以使用isset()方法檢測,如果是私有的則不行,因爲私有變量在外部訪問不到。爲了解決這種情況,我們只需要在類裏面定義一個__isset()方法,當在類外部使用isset()函數來檢測對象私有成員變量是否設定時,就會自動調用類裏的__isset()方法來完成操作。

  1. __isset()方法的作用
    當對不可訪問屬性調用isset()或empty()時,__isset()會被調用
  2. 例子
<?php
class Person
{ 
 private $name;
 private $age;
 private $sex;
 
 function __construct($name='Bob',$age="16")
 { 
     $this->name = $name;
     $this->age = $age;
 }
 
 function __isset($content)
 {
  echo "當在類外部使用isset()函數檢測私有成員變量{$content}時,自動調用\n";
  if (isset($this->$content)) {
   echo $content.":true\n";
  } else {
   echo $content.":false\n";
  }
 }                                                                                       
}

$person = new Person();
echo isset($person->name);
echo isset($person->age);
echo isset($person->sex);
// Output:
// 當在類外部使用isset()函數檢測私有成員變量name時,自動調用
// name:true
// 當在類外部使用isset()函數檢測私有成員變量age時,自動調用
// age:true
// 當在類外部使用isset()函數檢測私有成員變量sex時,自動調用
// sex:false

這裏記錄一下之前踩過的坑
在這裏插入圖片描述

八. __unset(),當對不可訪問屬性調用unset()時被調用

我們首先了解一下unset()函數
,unset()函數的作用是刪除指定變量且返回true,參數爲要刪除的變量。注意:unset()函數銷燬的只是局部變量並非全局變量。
假如在一個對象外部要去刪除對象內部的成員變量時,這裏也分兩種情況,如果對象裏的成員屬性是公有的則可以用這個函數在對象外面刪除對象的公有屬性,如果是私有的則沒有權限刪除。
同樣只要在類里加上一個__unset()方法,就可以在對象外部使用unset()函數刪除內部的私有成員屬性了。

  1. __unset()方法的作用
    當對不可訪問屬性調用unset()時,__unset()會被調用
  2. 例子
<?php
class Person
{ 
 private $name;
 private $age;
 
 function __construct($name="Bob",$age="16")
 { 
     $this->name = $name;
     $this->age = $age;
 }
 
 function __unset($content)
 {
  echo "當在類外部使用unset()函數來刪除私有成員{$content}時自動調用\n";
  echo isset($this->$content);
 }
 
 function say(){
  echo "name:".$this->name.",age:".$this->age;
 }                                                                                   
}

$person = new Person();
unset($person->name);
unset($person->age);
$person->say(); //上面unset銷燬的是局部變量,而再調用環境中的變量時與unset()之前保持一致
// Output:
// 當在類外部使用unset()函數來刪除私有成員name時自動調用 1
// 當在類外部使用unset()函數來刪除私有成員age時自動調用 1
// name:Bob,age:16

九. __sleep(),執行serialize()時,先會調用這個函數

serialize()函數會檢查類中是否存在一個魔術方法__sleep(),如果存在,則該方法會被優先調用,然後再執行反序列化操作。
此功能可以用於清理對象並返回一個包含對象中所有應被反序列化的變量名稱的數組。如果該方法並未返回任何內容,則NULL被反序列化,併產生一個E_NOTICE級別的錯誤。注意:__sleep()不能返回父類私有成員的名字,否則會產生一個E_NOTICE級別的錯誤。可以用Serializable接口來替代。

  1. __sleep()方法的作用
    __sleep()方法常用於提交未提交的數據,或類似的清理操作。同時如果有一些很大的對象但不需要全部保存,這個功能就很好用
  2. 例子
<?php
class Person
{ 
 public $name;
 public $age;
 
 function __construct($name,$age="16")
 { 
     $this->name = $name;
     $this->age = $age;
 }
 
 function __sleep(){
  echo "當在類外部使用serialize()時會自動調用__sleep()方法\n";
  return array('name','age');//這裏必須返回一個數組,裏面的元素表示返回的屬性名稱
 }
}

$person = new Person("Bob");
echo serialize($person);
// Output:
// 當在類外部使用serialize()時會自動調用
// O:6:"Person":2:{s:4:"name";s:3:"Bob";s:3:"age";s:2:"16";}

十. __wakeup(),執行unserialize()時,先會調用這個函數

unserialize()函數在反序列化之前會檢查類中是否存在__wakeup()方法,如果存在則優先調用__wakeup()方法

  1. __wakeup()方法的作用
    __wakeup()經常用在反序列化操作中,例如重新建立數據庫連接或執行其他初始化操作。
  2. 例子
<?php
class Person
{ 
 public $name;
 public $age;
 
 function __construct($name,$age="16")
 { 
     $this->name = $name;
     $this->age = $age;
 }
 
 function __sleep(){
  echo "當在類外部使用serialize()時會自動調用__sleep()方法\n";
  return array('name','age');//這裏必須返回一個數組,裏面的元素表示返回的屬性名稱
 }
 
 function __wakeup(){
  echo "當在類外部使用unserialize()時會自動調用__wakeup()方法\n";
  $this->name = "Alice";
  $this->age = 18; //這裏不必返回數據
 }
}

$person = new Person("Bob");
$a = serialize($person);
echo $a."\n";
var_dump(unserialize($a));
// Output:
// 當在類外部使用serialize()時會自動調用__sleep()方法
// O:6:"Person":2:{s:4:"name";s:3:"Bob";s:3:"age";s:2:"16";}
// 當在類外部使用unserialize()時會自動調用__wakeup()方法
// C:\Users\zeng\Desktop\ll.php:24:
// class Person#2 (2) {
//   public $name =>
//   string(5) "Alice"
//   public $age =>
//   int(18)
// }

十一. __toString(),類被當成字符串時的迴應方法

  1. __toString()方法的作用
    __toString()方法用於當一個類被當成字符串時如何響應,如echo $person;。注意:此方法必須返回一個字符串否則會發出一條E_RECOVERABLE_ERROR級別的錯誤。
  2. 例子
<?php
class Person
{ 
 public $name;
 public $age;
 
 function __construct($name,$age="16")
 { 
     $this->name = $name;
     $this->age = $age;
 }
 
 function __toString(){
  return "當一個類被當做字符串時調用__toString()方法";
 }
}

$person = new Person("Bob");
echo $person;
// Output:
// 當一個類被當做字符串時調用__toString()方法

十二. __invoke(),調用函數的方式調用一個對象時的迴應方法

  1. __invoke()方法的作用
    當嘗試以調用一個函數的方式調用一個對象時,__invoke()方法會被自動調用,如$person()
  2. 例子
<?php
class Person
{ 
 public $name;
 public $age;
 
 function __construct($name,$age="16")
 { 
     $this->name = $name;
     $this->age = $age;
 }
 
 function __invoke(){
  echo "當嘗試以調用一個函數的方式調用對象時調用__invoke()方法";
 }
}

$person = new Person("Bob");
$person();
// Output:
// 當嘗試以調用一個函數的方式調用對象時調用__invoke()方法

十三. __set_state(),調用var_export()導出類時,此靜態方法會被調用

var_export()函數返回傳遞給該函數的變量的結構信息,它和var_dump()類似,不過其返回的是一個合法的PHP代碼。

  1. __set_state()方法的作用
    當調用var_export()函數時,此靜態方法會被自動調用,本方法的唯一參數是一個數組。
  2. 例子
<?php
class Person
{ 
 public $name;
 public $age;
 
 static function __set_state($array){
  $a = new Person();
  $a->name = $array['name'];
  $a->age = $array['age'];
  echo $a;
 }
}

$person = new Person();
$person->name = "Alice";
$person->age = 18;
var_export($person);
// Output:
// Person::__set_state(array('name' => 'Alice','age' => 18,))

對於該方法本人函數比較懵逼,沒看出來到底有啥用,可能還是菜吧。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章