前言
Php可以說是一個面向對象的語言,php的類中有自己獨有的一些方法,不同於別的編程語言,php在定義類中除了我們自己定義的屬性方法以外,Php還有一寫魔術方法,當我們把這些方法寫出來後,我們並不需要自己去調用。系統就會在觸發某些條件之後自動調用。
注意,當我們沒有寫這些魔術方法時,系統不會去調用這些魔術方法。
php提供的魔術方法有很多,這裏我們只介紹常用的幾個。
__get讀取不可訪問或不存在的屬性的值時,__get() 會被調用。
__set在給不可訪問或不存在的屬性賦值時,__set() 會被調用。
__isset() 當對不可訪問或不存在屬性調用 isset() 或 empty() 時,__isset() 會被調用。
__unset();當對不可訪問或不存在的屬性調用 unset() 時,__unset() 會被調用。
__call()在對象中調用一個不可訪問或不存在的方法時,__call() 會被調用。
__clone()可以防止別人克隆我們的對象。
- __tostring();方法用於一個類被當成字符串時應怎樣迴應。例如 echo $obj; 應該顯示些什麼。
- __construct();PHP 5 允行開發者在一個類中定義一個方法作爲構造函數。具有構造函數的類會在每次創建新對象時先調用此方法。
- __destruct();PHP 5 引入了析構函數的概念,析構函數會在到某個對象的所有引用都被刪除或者當對象被顯式銷燬時執行。
你會發現這些魔術方法的前面都有兩個下劃線__這是因爲PHP 將所有以\ __(兩個下劃線)開頭的類方法保留爲魔術方法。所以在定義類方法時,除了上述魔術方法,建議不要以\ __ 爲前綴。
下面我們單個的介紹每個魔術方法是怎麼使用的。
魔術方法
__get()和__set()
__get():讀取不可訪問或不存在的屬性的值時,__get() 會被調用。
__set():在給不可訪問或不存在的屬性賦值時,__set() 會被調用。
在類中當屬性的修飾符是protected和private的時候,在類的外部不能通過對象名的形式進行訪問,如果強行讀取不可訪問的屬性,並且你在類的內部寫了__get函數,這時候系統就會自動的調用__get魔術方法,當你強行修改不可訪問屬性值得時候,__set魔術方法就會被執行。
示例:
<?php
class Cat{
protected $name;
protected $age;
protected $sex;
public function __construct($name,$age,$sex){
$this -> name = $name;
$this -> age = $age;
$this -> sex = $sex;
}
//__set方法,可以處理你自己的邏輯
public function __set($name,$value){
echo 'set方法被執行了<br>';
//這裏使用這個函數判斷當前類中有沒有這個屬性,防止屬性出現null的情況。
if(property_exists($this, $name)){
$this -> $name = $value;
}else{
echo '你要設置的屬性不存在';
}
}
//__get方法,可以處理你自己的邏輯
public function __get($name){
echo 'get方法被執行了<br>';
if(isset($this->$name)){
return $this -> $name;
}else{
echo '你要的屬性不存在,或者屬性值爲空';
}
}
}
$cat = new Cat('小花',2,'雌');
echo $cat -> name . '<br>'; //讀取不可訪問的屬性值得時候,get方法被執行
$cat -> age = 5; //修改不可訪問的屬性值set方法被執行
echo $cat -> age;
property_exists()函數:檢查對象或類是否具有該屬性
__isset()和__unset()
__isset():當對不可訪問或不存在屬性調用isset() 或 empty() 時,__isset() 會被調用。
__unset():當對不可訪問或不存在的屬性調用 unset() 時,__unset() 會被調用。
在類的外部對對象的不能訪問屬性使用isset函數或empty函數的時候或者這個屬性在類中都沒有定義。魔術方法__isset()就會執行,而進行unset操作是__unset就會自動調用。
示例:
<?php
class Cat{
protected $name;
protected $age;
protected $sex;
public function __construct($name,$age,$sex){
$this -> name = $name;
$this -> age = $age;
$this -> sex = $sex;
}
//__isset方法,在類中可以對類的屬性進行判斷,並返回。
public function __isset($name){
echo 'isset方法執行了<br>';
return isset($this -> $name);
}
//__unset方法
public function __unset($name){
echo 'unset方法執行了<br>';
if(property_exists($this,$name)){
unset($this -> $name);
}else{
echo '你要銷燬的屬性不存在';
}
}
}
$cat = new Cat('小花',2,'雌');
echo isset($cat -> name);
unset($cat->age);
echo '<pre>';
var_dump($cat);
__call()
__isset():在對象中調用一個不可訪問或不存在的方法時,__call() 會被調用。
因爲php語言不支持函數的重載,可以使用這個魔術方法進行重載。
示例:
<?php
class Math{
private function add($a,$b){
return $a + $b;
}
private function add1($a,$b,$c){
return $a + $b + $c;
}
//這個魔術方法中有兩個參數,第一個參數是傳過來的函數名,第二個參數是傳過來的方法中的參數組成的數組。
public function __call($method,$arr_value){
if($method == 'add'){
//得到數組的數量,確定使用那個方法。
$total = count($arr_value);
if($total == 2){
return $this -> add($arr_value[0],$arr_value[1]);
}else if($total == 3){
return $this -> add1($arr_value[0],$arr_value[1],$arr_value[2]);
}
}
}
}
$math = new Math();
echo $math -> add(1,2) . '<br>';//私有的方法,沒有權限,會調用call方法.
echo $math -> add(1,2,3);
在php中同一類中一定不能有方法名相同的函數。不然後報錯。
__clone()
__clone():可以防止別人克隆我們的對象。
php語言中有一種機制叫做克隆,如果定義了 __clone()方法,則新創建的對象(複製生成的對象)中的 __clone()方法會被調用。
程序員可以通過克隆把對象進行整體的克隆,但是有時我們不希望別人克隆我們的對象,比如單列模式,這時使用克隆可以解決。
示例:
<?php
class Cat{
public $name;
public $age;
public function __construct($name,$age){
$this -> name = $name;
$this -> age = $age;
}
public function showInfo(){
echo '姓名是:' . $name . ' ' . '年齡是:' . $age;
}
private function __clone(){
}
}
$cat = new Cat('小花',2);
echo '<pre>';
var_dump($cat);
$cat2 = clone $cat;
var_dump($cat2);
注意在這裏魔術方法的權限修飾符是private,私有的。
__tostring()
__tostring方法用於一個類被當成字符串時應怎樣迴應。例如 echo $obj;
當我們嘗試把一個對象當成字符換進行echo輸出的時候,類的tostring方法就會默認被調用,在這個方法中我們可以定義對象應該輸出什麼。
示例:
<?php
class Dog{
private $name;
private $age;
private $color;
public function __construct($name,$age,$color){
$this -> name = $name;
$this -> age = $age;
$this -> color = $color;
}
//定義tostring方法
public function __toString(){
return '名字是:' . $this ->name . ' ' . '年齡是:' . $this -> age . ' ' . '顏色是:' . $this ->color;
}
}
$dog = new Dog('小白',4,'red');
echo $dog;
注意:在tostring中必須要有一個返回值。
__construct()
__construct():PHP 5 允行開發者在一個類中定義一個方法作爲構造函數。具有構造函數的類會在每次創建新對象時先調用此方法。
在類中定義構造函數一般是完成創建對象時,對象的初始化。當我們沒有定義構造方法的時候,系統會調用他自己默認的構造函數,這個構造函數是一個無參的構造函數。
示例
<?php
class Cat{
protected $name;
protected $age;
protected $sex;
//定義一個構造函數,完成對屬性的初始化。
public function __construct($name,$age,$sex){
$this -> name = $name;
$this -> age = $age;
$this -> sex = $sex;
}
}
$cat = new Cat('小白',12,'雄');
echo '<pre>';
var_dump($cat);
__destruct()
__destruct();PHP 5 引入了析構函數的概念,析構函數會在到某個對象的所有引用都被刪除或者當對象被顯式銷燬時執行。
析構函數會在函數銷燬前執行,在這裏面我們可以對用到的資源進行釋放,比如數據庫。
示例
<?php
class DaoMysql{
protected $link;
public function __construct($host,$user,$pwd){
$this -> link = @mysql_connect($host,$user,$pwd);
}
public function getLink(){
return $this -> link;
}
//析構函數,用來釋放數據庫資源。
public function __destruct(){
mysql_close($this->link);
}
}
$daoMysql = new DaoMysql('localhost','root','123456');
$sql = 'select * from tb1';
mysql_select_db('test');
mysql_query('set names utf8');
//通過對象的到裏面的鏈接對象。
$res = mysql_query($sql,$daoMysql -> getLink());
echo '<pre>';
while($row = mysql_fetch_assoc($res)){
var_dump($row);
}
//當類中沒有析構函數的時候,把對象置爲空,下面的獲取數據還能執行,
//當類中有析構函數的時候,把對象置爲空,下面的獲取數據會出錯。說明成功的在析構方法中把數據庫連接釋放掉了。
$daoMysql = null;
$res = mysql_query($sql);
echo '<pre>';
while($row = mysql_fetch_assoc($res)){
var_dump($row);
}
總結
在php中,這些魔術方法大多數都是我們操作不可操作的數據時,系統觸發執行。區別於別的語言,也可以說是php的一大特色。(- _ -);