在php的語法中,有一些系統自帶的方法名,均以雙下划線開頭,它會在特定的情況下被調用。即所謂的魔法函數。它們在面向對向編程中起着至關重要的作用。所以個人覺得很有必要整理一下。下面就php的15個魔法函數做一個詳細整理:
1. __construct() 和 __destruct()
__construct() 對象初始化時會調用此方法(對於內核而言是指初始化完成后調用此方法).此方法用得比較多。__destruct() 當對象銷毀時會調用此方法.那么什么時候對象會銷毀呢?一是用戶主動銷毀對象,二是當程序結束時由引擎自動銷毀
class People {
protected $_alive;
public function __construct()
{
$this->_alive = true;
echo 'Birth'.PHP_EOL;
}
public function __destruct()
{
$this->_alive = false;
echo 'Die'.PHP_EOL;
}
}
//主動銷毀對象
$test = new Test();
unset($test);
sleep(1);
//程序完成后自動銷毀對象
$test = new Test();
sleep(1);
2. __get() 和 __set()
面向對象編程中使用頻率很高的兩個方法.當設置和獲取對象的屬性不允許訪問時性,此方法會被調用。一定注意是不存在或不允許被讀寫時才會被調用。
因此對於一個對象,其屬性不確定時,用這兩個方法效果很好。
__get($name) 獲取對象不存在的屬性或無法訪問的屬性時調用.$name表示要獲取的屬性名
__set($name, $value) 設置對象不存在的屬性或無法訪問的屬性時調用.$name表示要設置的屬性名,$value表示要設置的值.
//例如:我們可以構建一個不確定屬性的數據記錄類
class Record {
protected $_data;
public function __get($name)
{
if (isset($this->_data[$name])) {
return $this->_data;
}
return false;
}
public function __set($name, $value)
{
$this->_data = $value;
}
}
$record = new Record();
$record->name = 'andrew';
echo 'My name is '.$record->name.PHP_EOL;
3. __isset() 和 __unset()
這兩個方法用得比較少些。當調用方法isset()判斷對象是否存在某屬性, 調用unset()注銷某屬性時。且當這些屬性不存在或不可訪問時,會分別調用__isset()和__unset()方法
與前面的__get()和__set()略同。都是某屬性不存在或不可訪問時被調用
__isset($name) 當調用方法isset()方法判斷不可訪問的類屬性時調用.$name表示屬性名.
__unset($name) 當調用方法unset()方法刪除不可訪問的類屬性時調用.$name表示屬性名.
//例如:
class People {
public $name;
public $sex;
private $_age;
public function __construct($name, $sex, $age)
{
$this->name = $name;
$this->sex = $sex;
$this->_age = $age;
}
public function __isset($name)
{
echo 'The property '.$name.' not exists'.PHP_EOL;
}
public function __unset($name)
{
echo 'The property '.$name.' can not be unset'.PHP_EOL;
}
}
$people = new People('andrew', 'male', 28);
isset($people->name);
isset($people->real_name);
unset($people->_age);
4. __call() 和 __callStatic()
前面,我們發現,在獲取對象的屬性時,如果此屬性不存在會調用__get()方法。那么如果調用此對象的方法時,如果此方法不存在呢?php引擎會自動調用__call()方法。
同樣,如果調用的是靜態方法,且不存在時會調用__callStatic()方法。需要注意的是,__callStatic()使用時是一個靜態方法,且僅在php5.3以上版本才支持.
__call($method, $args) 調用對象方法不存在或不允許被調用時此方法會被調用。$method表示調用的方法名,$args表示調用的參數
__callStatic($method, $args) 調用對象的靜態方法不存在或不允許被調用時此方法會被調用。$method表示調用的方法名,$args表示調用的參數.
//例如:我們假定人只有跳走兩種行為
class People {
public function jump()
{
echo 'I can jump'.PHP_EOL;
}
public function walk()
{
echo 'I can walk'.PHP_EOL;
}
public function __call($method, $args)
{
echo 'I can not '.$method.PHP_EOL;
}
//此方法必須是靜態方法,且在php5.3版本下可用
public static function __callStatic($method, $args)
{
echo 'We can not'.$method.PHP_EOL;
}
}
$people = new People();
$people->jump();
$people->walk();
$people->fly();
People::fly();
5. __sleep() 和 __wakeup()
這兩個方法,咋一看,就是睡覺和喚醒嘛。那跟對象有什么關系?有時候該用的時候也想不起來。其實,我們簡單點記,在php中有一個讓對象睡覺的方法,叫searialize(),
它會將對象的各屬性序列化以方便保存起來。而unsearialize()方法是將保存的序列化的數據解開變成對象。也叫喚醒。相對應的,當睡覺時,php會調用__sleep()方法,它
的返回值必須是一個數組,表示需要保存的屬性項, 對於文件句柄,數據庫連接等資源類型的數據是不能被序列化保存的。同理喚醒對象時,php會調用__wakeup()方法,
但與__sleep()不同的是,它返回值為空。被保存的屬性都會被解開。那它有什么用呢?剛我們說了,searialize是不能保存資源的。那么喚醒時如果我們想用到這些資源怎么
辦?回答很肯定,重新創建?那在哪里創建合適呢?當然是__wakeup()方法里面,因為每次喚醒時都會調用此方法嘛。這下我們很清楚這兩個方法的用途了。
__sleep() 當調用searialize()方法時調用,返回值為數組,表示需要序列化的數據項.
__wakeup() 當調用unsearizlie()方法時調用。一般用來在喚醒時初始化資源對象.
//例如我們有一個用戶類,用戶名和性別都是類屬性。用戶的密碼存在文件中
Class User {
public $username;
public $sex;
public $passFile;
private $_password;
public function __construct($username, $sex, $passFile)
{
$this->username = $username;
$this->sex = $sex;
$this->passFile = $passFile;
$this->_password = file_get_contents($passFile);
}
public function getPassword()
{
return $this->_password;
}
public function __sleep()
{
return array(
'username', 'sex', 'passFile',
);
}
public function __wakeup()
{
$this->_password = file_get_contents($this->passFile);
}
}
$user = new User('andrew', 'male', 'pass.data');
$serializeData = serialize($user);
echo $serializeData.PHP_EOL;
$user = unserialize($serializeData);
echo $user->getPassword().PHP_EOL;
6. __toString()
當對象在需要轉換成字符串時,會調用此方法。例如,echo對象時,將對象強制轉換為string類型時, 用於字符串參數的函數中.注意:此方法的返回值必須為字符串。
//例如:
class Info {
public function __toString()
{
return "info";
}
}
$info = new Info();
echo $info.PHP_EOL;
echo md5($info).PHP_EOL;
echo (String) $info.PHP_EOL;
echo substr($info, 0, 2).PHP_EOL;
7. __clone()
此方法在復制對象時被調用。我們知道在php中.$a為一個對象,$b=$a時。$b為$a的引用。當$a發生改變時。$b也會隨之發生變化。那么為了使$b不發生變化,我們需要用$b=clone $a;
那么,當$a在調用clone的時候,引擎會自動調用__clone()方法
//例如:以下一個簡單的例子
class Data {
public $value;
public function __clone()
{
echo "Clone myself".PHP_EOL;
}
}
$data = new Data();
$data->value = 4;
$newData = clone $data;
$data->value = 5;
echo "The data value is: ".$data->value.PHP_EOL;
echo "The new data value is: ".$newData->value.PHP_EOL;
//對面向對象比較熟的同學,一定對單例模式不陌生。PHP做單例模式的時候要記住把clone方法給禁掉。因為在單例模式中,是不允許復制對象的。如下例
class OnlyOne {
//單例對象
private static $_instance;
//不允許外部和子類調用初始化方法
private function __construct()
{}
//不允許復制
public function __clone()
{
throw new Exception('Not allow to clone me');
}
//獲取單例對象
public static function getInstance()
{
if (self::$_instance != null) {
return self::$_instance;
}
self::$_instance = new self();
return self::$_instance;
}
}
$onlyOne = OnlyOne::getInstance();
$newOne = clone $onlyOne;
8. __autoload()
autoload顧名思義就是自動加載。它主要用來自動加載類。那如何自動加載呢?我們都知道在php中,要使用另外一個文件中的類需要用require或include方法
(包括require_once和include_one)導入進來。那么如果我要使用的類未被導入,則引擎會自動調用__autoload()方法。利用此特性,當我們的類名和類文件有規律
地存放時,我們可以使用__autoload()方法,根據需導入的類名,讓程序自動導入文件。此函數在許多的MVC框架中起着重要的作用。
__autoload($name) $name表示需要自動導入的類名
//我們制訂規則類名以目錄名加下載線拼接而成。例如:類Model_Config_Xml表示Model/Config/Normal.php文件.我們如何實現自動加載
//有類文件Model/Config/Normal.php內包含類如下:
class Model_Config_Normal {
public function __construct()
{
echo "Init Model_Config_Normal".PHP_EOL;
}
}
function __autoload($name)
{
$classPath = str_replace('_', DIRECTORY_SEPARATOR, $name);
require_once("$classPath.php");
}
//此時將無需再require('Model/Config/Normal.php')
$config = new Model_Config_Normal();
9. __set_state()
這個方法用得不多。了解這個方法前,需要先知道var_export()函數,var_export()和var_dump()類似,輸出一個變量的字符串表示。他與var_dump的區別在於它的返回結果的是合法的
php代碼.此代碼可以被eval執行. 注意:此方法是一個靜態方法,且在php5.1以上版本才支持。
//例如:
class Test {
public $name;
public $age;
public static function __set_state($data)
{
$obj = new Test();
$obj->name = $data['name'];
$obj->age = $data['age'] + 1;
return $obj;
}
}
$test = new Test();
$test->name = 'andrew';
$test->age = 27;
$code =var_export($test, true);
echo $code.PHP_EOL;
eval('$new='.$code.';');
var_dump($new);
10. __invoke()
這個方法我剛開始接觸的時候,一眼望去,真看不出來它到底干嘛的。主要是不明白invoke是啥意思。后來查了字典才明白。意思是呼叫。英語差傷不起呀。
在php中這個方法用於,把對象當方法用的時候。此方法會被調用。很簡單。注意,此方法僅5.3以上版本支持。
class Invoke {
public function __invoke()
{
echo 'I can run'.PHP_EOL;
}
}
$invoke = new Invoke();
$invoke();