php中的魔術方法

魔術方法:
是指某些情況下,會自動調用的方法,稱爲魔術方法
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: 如果userModel>xxx,,,,xxx, user->xxx = $_POST[‘xxx’];
這不就出錯了嗎?

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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章