魔術方法:
是指某些情況下,會自動調用的方法,稱爲魔術方法
PHP面向對象中,提供了這幾個魔術方法,
他們的特點 都是以雙下劃線__開頭的
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state() 和 __clone()
__construct :構造方法
__destruct :析構方法
__clone() :克隆方法,當對象被克隆時,將會自動調用
__clone()
class Human{
public age=22;
public function __clone(){
echo "有人要克隆我,是假的!";
}
}
$lisi=new Human();
$zhangsan=clone $lisi; //"有人要克隆我,是假的!"
接下來講6個,在項目中,尤其是自己想寫框架時,很實用的幾個函數
__call(), __callStatic(), __get(), __set(), __isset(), __unset(),
01 __get()
class Human{
private $money="30兩";
protected $age="24歲";
public $name="lisi";
}
$lisi=new Human();
echo $lisi->name; //lisi 正常輸出
echo $lisi->age; //權限錯誤
echo $lisi->friend; //出錯,未定義
接下來我們利用魔術方法來做改進:
class Human{
private $money="30兩";
protected $age="20";
public $name="lisi";
public function __get($p){
echo "你想訪問我的".$p."屬性";
}
}
$lily = new Human();
// echo $lily->name; //lily
echo $lily->age; // '你想訪問我的age屬性 :)
echo $lily->money; // 你想訪問我的money屬性 :)
echo $lily->friend; // 你想訪問我的friend屬性 :)
總結:
可以總結出:
當我們調用一個權限上不允許調用的屬性,和不存在的屬性時,
__get魔術方法會自動調用,
並且自動傳參,參數值是屬性名.
流程:
$lily->age--無權-->__get(age);
$lily->friend--沒有此屬性-->__get('friend');
生活中,你幫別人看守小賣店
買牙刷—>好,給你牙刷
買毛巾—>好,給你毛巾
這個POS機挺好—> (pos是商店的工具,私有的,不賣的:”你無權買”), 但是我們用__get方法,
就有一個友好的處理機會.
系統會直接報錯,甚至fatal error,通過__get,我們就能自定義用戶訪問時,的處理行爲.
02 __set()
class Human{
private $money="30兩";
protected $age="24歲";
public $name="lisi";
}
$lily->aaa = 111;
$lily->bbb = 222;
print_r($lily);//aaa,bbb兩個屬性竟然都給加上了.其實,對象就是一個屬性集,在js中更明顯.但是如果這麼隨便就能加了屬性,導致這個對象屬性過多,不好管理
改進:
class Stu {
private $money = '30兩';
protected $age = 23;
public $name = 'Hmm';
public function __set($a,$b) {
echo '你想設置我的',$a,'屬性','<br />';
echo '且值是',$b,'<br />';
}
}
$hmm = new Stu();
$hmm->aaa = 111;
$hmm->money = '40兩';
$hmm->age = '28';
print_r($hmm);
$hmm->name = 'HanMM';
print_r($hmm);
/*
如上,總結出 __set的作用
當爲無權操作的屬性賦值時,
或不存在的屬性賦值時,
__set()自動調用
且自動傳2個參數 屬性 屬性值
例:
$hmm->age = 28 ---無權---> __set('age',28);
*/
03 __isset() __unset()
class Dog {
public $leg = 4;
protected $bone = '豬腿骨';
public function __isset($p) {
echo '你想判斷我的',$p,'屬性存不存在<br />';
return 1;
}
public function __unset($p) {
echo '你想去掉我的',$p,'?!<br />';
}
}
$hua = new Dog();
if(isset($hua->leg)) {
echo $hua->leg;
}
if(isset($hua->tail)) {
echo '有tail屬性';
} else {
echo '沒有tail';
}
/***
__isset() 方法,
當 用isset() 判斷對象不可見的屬性時(protected/private/不存在的屬性)
會引發 __isset()來執行
問: isset($obj->xyz) 屬性,爲真,
能說明 類聲明瞭一個xyz屬性嗎?
答:不能
***/
echo '<hr />';
echo '__unset測試';
print_r($hua);
unset($hua->leg);
print_r($hua);
unset($hua->tail);
unset($hua->bone);
/***
__unset()方法
當 用unset 銷燬對象的不可見屬性時,
會引發 __unset();
unset($hua->tail)----沒有tail屬性---->__unset('tail');
魔術方法在thinkphp中的使用
剛纔 我們用TP做了一個用戶註冊,註冊時的代碼在下面
按我們以前的做法,
把POST來的數據,拼接sql,然後查詢.
但是在TP中的做法,有點奇怪,
他是把收到的信息,
賦給了一個對象的屬性.
然後對象->add()方法,就寫入到數據庫了.
很方便 .
思考:
1: userModel就有username屬性供你去賦值嗎?
2: 如果
這不就出錯了嗎?
3:還有一個問題: userModel 有一些屬性,很正常,比如有5個屬性
a,b,c,d,e
我在註冊時, 又動態設置了屬性, f,g,h,i
疑問: 在拼接sql時,要把a,b,c,d,e忽略掉才行.
又怎麼忽略.
答:用魔術方法來解決
通過__set()方法,
把屬性的設置—>都放到數組裏.
處理時,專門處理這個數組就可以了.
這樣,就不會和其他屬性相沖突
*/
/*
TP中的一段用戶註冊代碼
$userModel->username = $_POST['username'];
$userModel->email = $_POST['email'];
if($num = $userModel->table('user')->add()) {
echo '註冊成功';
} else {
echo 'fail';
}
*/
class UserModel {
protected $email = '[email protected]';
protected $data = array();
public function __set($k,$v) {
// $this->$k = $v; //並沒有真正賦成自己的屬性
$this->data[$k] = $v; // 而是放在一個數組裏
}
public function __get($p) {
return isset($this->data[$p]) ? $this->data[$p] : NULL;
}
public function __unset($p) {
unset($this->data[$p]);
}
public function __isset($p) {
return isset($this->data[$p]);
}
public function add() {
$sql = 'insert into table (';
$sql .= implode(',',array_keys($this->data));
$sql .= ') values (\'';
$sql .= implode("','",array_values($this->data));
$sql .="')";
return $sql;
}
}
echo '<pre>';
$userModel = new UserModel();
print_r($userModel);
$userModel->username = 'lisi';
$userModel->email = '[email protected]';
print_r($userModel);
//echo $userModel->add();
unset($userModel->email);
print_r($userModel);