PHP面向物件核心(一)——序列化與魔術方法
PHP面向物件核心(一)
(原創內容,轉載請註明來源,謝謝)
一、物件儲存——serialize與unserialize
物件是儲存類的屬性的鍵值對,類似於陣列的鍵值對。
物件在進行serialize(序列化)時,會連帶類名、屬性值、屬性佔用長度一併儲存,當使用unserialize(反序列化)時可以還原物件。但是反序列化需要包含類原先定義的程式碼,否則還原後無法執行物件所屬類的方法。
作用:將物件序列化,以便於將物件以字串的形式儲存在檔案或資料庫中。
示例如下:
//定義一個水果類 class fruit{ private $shape; private $color; public function __construct($shape,$color){ $this->shape =$shape; $this->color =$color; } public function eatMethod($hasPeel){ echo ‘反序列化成功’; } } //定義蘋果物件 $apple = newfruit(‘round’, ‘red’); $strApple =serialize($apple); echo $strApple; //執行結果:O:5:"fruit":2:{s:12:"fruitshape";s:5:"round";s:12:"fruitcolor";s:3:"red";} //還原apple物件方式:反序列化 $objApple =unserialize($strApple);//$objApple==$apple
二、魔術方法
魔術方法是PHP的“語法糖”,都是以兩個下劃線開頭的方法,在面向物件中具有重要作用。魔術方法在類中定義,當對於把類例項化的物件進行一些特定操作時,會觸發相應的魔術方法。
1、__construct與__destruct
__construct稱為建構函式,在每個類被例項化的時候,該函式會自動被呼叫。PHP不同於java,建構函式無法被重寫。
建構函式通常用於例項化類時對類的屬性進行賦值,還有進行資料庫連線等操作。具體用法在上面水果類的定義中已經提到。
__destruct稱為解構函式,與建構函式相對應,這個函式是在某個物件的所有引用被刪除,或者物件被顯示銷燬時,自動呼叫的。該函式也不能重寫。
解構函式通常用於釋放儲存空間、斷開資料庫連線等操作。
2、__get與__set
當要對一個類定義的private屬性進行獲取或者賦值的操作時,如果沒有在類中定義__get、__set,PHP會爆出Fatal錯誤。但是,如果定義了方法,會自動執行方法。
這兩個方法主要是對於操作類的私有方法時,可以進行更為靈活的處理,再避免報錯增強程式健壯性的同時,又可以根據設定得到想要的結果,保證程式是可控的。
根據面向物件的封裝性的思想,通常是不建議物件直接操控類的屬性。這兩個方法就可以對操作屬性進行把控。
示例如下:
class testControlProp{ private $propArray; public function__get($name){ if(!property_exists($this,$name)){ return'無此屬性<br />'; }else{ return$this->$name.'<br />'; } } public function__set($name, $val){ if(!property_exists($this,$name)){ echo'無此屬性<br />'; }else{ if(!is_array($val)){ echo'對屬性的設定不合法<br />'; }else{ $this->$name= $val; echo'success<br />'; } } } } $test = new testControlProp(); $test->propArray = 'a1';//返回結果是對屬性設定不合法 $test->propArray = array(1, 2);//返回success echo $test->prop;//返回無此屬性 echo $test->propArray;//返回array
上述方法實現把控物件對其屬性的操作,保證設定的屬性都是想要的格式或內容,保證獲取的屬性都是有效的經過處理的。
3、__toString
當echo類的例項時,會自動呼叫該方法,如果沒有定義該方法,則會報錯。
__toString方法可以自定義echo的內容,讓輸出更人性化。
因此,可以使用此方法自定義需要輸出的結果,以起到自定義serialize的作用,更加節約儲存空間。
4、__call、__callStatic
當呼叫類沒有定義的方法時,如果類中沒有定義__call則會報錯(__callStatic則是呼叫沒有定義的static方法)。
__call方法具有重要作用,可以實現動態建立和延遲繫結功能。
下面實現資料庫查詢條件where的動態繫結功能。
結果如下:
PHP原始碼如下:
<?php
class Db{
private$server; //資料庫伺服器名稱
private $username; // 連線資料庫使用者名稱
private $password; // 連線資料庫密碼
private $database; // 資料庫的名字
private$conn;//資料庫連線
private$sql;
publicfunction __construct($server='localhost', $username='root', $password='root',$database='test'){
$this->server= $server;
$this->username= $username;
$this->password= $password;
$this->database= $database;
$dbConnection= new PDO('mysql:host=127.0.0.1;dbname=test','root','root');
//$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
//$dbConnection->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$this->conn= $dbConnection;
}
//動態查詢資料:
//格式:get_tablename_by_condintions1_conditions2(val1,val2)
publicfunction __call($name, $args){
$arrName= explode('_', $name);
$this->sql= ' select * from '.$arrName[1];
if(count($arrName)<3){
return$this->conn->query($this->sql);
}else{
$this->sql.= ' where ';
$arrCond= array();
for($i=3;$i<count($arrName);$i++){
$this->sql.= ' '.$arrName[$i].' = :'.$arrName[$i].' ';
if($i<count($arrName)-1){
$this->sql.= ' and ';
}
$arrCond[$arrName[$i]]= $args[$i-3];
}
$pre= $this->conn->prepare($this->sql);
$pre->execute($arrCond);
return$pre;//注意:需要return pre,而不是execute的結果,否則報錯
}
}
}
$db = new DB();
$result = $db->get_mytable();
echo '不帶查詢條件:<br />';
foreach($result as $val){
print_r($val);
echo'<br / >';
}
echo '<br />帶查詢條件<br/>' ;
$result =$db->get_mytable_by_name_status('a', 1);
//var_dump($result);die();
foreach ($result as $val) {
print_r($val);
echo'<br / >';
}
——written by linhxx 2017.06.20