1. 程式人生 > 其它 >PHP面向物件核心(一)——序列化與魔術方法

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