天天看點

PHP 類與對象 全解析(三)

目錄

PHP 類與對象 全解析( 一)

PHP 類與對象 全解析( 二)

PHP 類與對象 全解析(三 )

13.魔術方法

  定義:PHP把所有以__(兩個下劃線)開頭的類方法當成魔術方法

  __construct, __destruct (參看 構造方法和析構方法),

  __call, __callStatic, __get, __set, __isset, __unset (參看 重載),

  __sleep, __wakeup, __toString, __set_state 和 __clone 等方法在PHP中被稱為“魔術方法”(Magic methods)。

  你在命名自己的類方法時不能使用這些方法名。

  serialize()

  作用: 第一. 在序列化之前,關閉對象可能具有的任何資料庫連接配接等.

        第二. 指定對象中需要被序列化的成員屬性,如果某個屬性比較大而不需要儲存下來,可以不把它寫進__sleep要傳回的數組中,這樣該屬性就不會被序列化

  在用serialize序列化對象時,會自動調用__sleep方法,__sleep方法必須傳回一個數組,包含需要串行化的屬性。

       PHP會抛棄其它屬性的值, 如果沒有__sleep方法,PHP将儲存所有屬性,包括private屬性。

  unserialize()  從位元組流中建立了一個對象之後,馬上檢查是否具有__wakeup 的函數的存在。

  如果存在,__wakeup 立刻被調用。使用 __wakeup 的目的是重建在序列化中可能丢失的任何資料庫連接配接以及處理其它重新初始化的任務。

下面給出一個序列化的代碼:共serialize.php和unserialize.php兩個檔案。

<?php  
       class User   
       {   
           public $name;   
           public $id;  
      
           function __construct()   
           {   
               $this->id = uniqid();          //give user a unique ID 賦予一個不同的ID   
           }  
      
           function __sleep()   
           {      
               return(array("name"));        //do not serialize this->id 不串行化id  
           }  
      
           function __wakeup()   
           {   
               $this->id = uniqid();         //give user a unique ID   
           }   
       }  
      
       $u = new User;   
       $u->name = "HAHA";  
      
       $s = serialize($u);                   //serialize it 串行化 注意不串行化id屬性,id的值被抛棄  
      
       $u2 = unserialize($s);                //unserialize it 反串行化 id被重新指派  
      
         
       //$u and $u2 have different IDs $u和$u2有不同的ID   
       var_dump($u);                           
       var_dump($u2);   
    ?>        

---------- PHP debug ----------

object(User)#1 (2) {

["name"]=>

string(4) "HAHA"

["id"]=>

string(13) "47fa045529f69"

}

object(User)#2 (2) {

string(13) "47fa04552a49a"

---序列化--------反序列化--------------------

class ClassA {  
    var $int;  
    var $str;  
    var $bool;  
    var $obj;  
    var $pr;  
}  
   
$a = new ClassA();  
$a->int = 1;  
$a->str = "Hello";  
$a->bool = false;  
$a->obj = $a;  
$a->pr = &$a->str;  
   
echo serialize($a);  
//O:6:"ClassA":5:{s:3:"int";i:1;s:3:"str";s:5:"Hello";s:4:"bool";b:0;s:3:"obj";r:1;s:2:"pr";R:3;}        

  在這個例子中,首先序列化的對象是 ClassA 的一個對象,那麼給它編号為 1,接下來要序列化的是這個對象的幾個成員,第一個被序列化的成員是 int 字段,那它的編号就為 2,接下來被序列化的成員是 str,那它的編号就是 3,依此類推,到了 obj 成員時,它發現該成員已經被序列化了,并且編号為 1,是以它被序列化時,就被序列化成了 r:1; ,在接下來被序列化的是 pr 成員,它發現該成員實際上是指向 str 成員的一個引用,而 str 成員的編号為 3,是以,pr 就被序列化為 R:3; 了。

===============

//下面舉個簡單的例子,來說明 Serializable 接口的使用:序列化--------反序列化-

class MyClass implements Serializable  
    {  
        public $member;  
       
        function MyClass()  
        {  
            $this->member = 'member value';  
        }  
       
        public function serialize()  
        {  
            return wddx_serialize_value($this->member);  
        }  
       
        public function unserialize($data)  
        {  
            $this->member = wddx_deserialize($data);  
        }  
    }  
    $a = new MyClass();  
    echo serialize($a);  
    echo "\n";  
    print_r(unserialize(serialize($a)));         

/*

輸出結果為(浏覽器中的源代碼):

C:7:"MyClass":90:{<wddxPacket

version='1.0'><header/><data><string>member

value</string></data></wddxPacket>}

MyClass Object

(

    [member] => member value

)

是以如果想用其它語言來實作 PHP 序列化中的 C 标示的話,也需要提供一種這樣的機制,讓使用者自定義類時,

能夠自己在反序列化時處理 <data> 内容,否則,這些内容就無法被反序列化了。

*/

、、、、

  __sleep 和 __wakeup

serialize() 函數會檢查是否存在一個魔術方法 __sleep.如果存在,__sleep()方法會先被調用,

然後才執行序列化操作。這個功能可以用于清理對象,并傳回一個包含對象中所有變量名稱的數組。如果該方法不傳回任何内容,則NULL被序列化,導緻

一個E_NOTICE錯誤。

__sleep方法常用于送出未送出的資料,或類似的操作。同時,如果你有一些很大的對象,不需要儲存,這個功能就很好用。

與之相反,unserialize()會檢查是否存在一個__wakeup方法。如果存在,則會先調用 __wakeup方法,預先準備對象資料。

__wakeup經常用在反序列化操作中,否則是字元串;例如重建立立資料庫連接配接,或執行其它初始化操作

------------------------------------------------------------------------------------------------

14. Final關鍵字

  如果父類中的方法被聲明為final,則子類無法覆寫該方法; 如果一個類被聲明為final,則不能被繼承。

  文法:

 類使用 final 關鍵字的例子:

final class Person  
 {  
  ......  
 }  
    
  class BaseClass {  
    public function test() {  
     echo "BaseClass::test() called\n";  
    }  
      
    final public function moreTesting() {  
     echo "BaseClass::moreTesting() called\n";  
    }  
 }  
  
class ChildClass extends BaseClass {  
    public function moreTesting() {  
       echo "ChildClass::moreTesting() called\n";  
   }  
}  
        

---------------------------------------------

15.對象複制

對象複制可以通過clone關鍵字來完成(如果對象中存在__clone()方法,會先被調用)。對象中的 __clone()方法不能直接調用。

 $copy_of_object = clone $object;

clone 關鍵字用于克隆一個完全一樣的對象,

__clone() 

 __clone() 方法來重寫原本的屬性和方法。是深複制

如果想在克隆後改變原對象的内容,需要在類中添加一個特殊的 __clone() 方法來重寫原本的屬性和方法。

 __clone() 方法隻會在對象被克隆的時候自動調用。

clone 關鍵字用于克隆一個完全一樣的對象,__clone() 方法來重寫原本的屬性和方法。

對象克隆

有的時候我們需要在一個項目裡面使用兩個或多個一樣的對象,如果使用 new 關鍵字重新建立對象,再指派上相同的屬性,這樣做比較煩瑣而且也容易出錯。

PHP 提供了對象克隆功能,可以根據一個對象完全克隆出一個一模一樣的對象,而且克隆以後,兩個對象互不幹擾。

使用關鍵字 clone 來克隆對象。文法: $object2 = clone $object;

例子1:

2,

__clone()

__clone() 方法隻會在對象被克隆的時候自動調用。

//例子1:

/* 
class Person { 
    private $name; 
    private $age; 
 
    public function __construct($name, $age) { 
        $this->name=$name; 
        $this->age=$age; 
    } 
 
    public function say() { 
        echo "my name is :".$this->name."<br />"; 
        echo "my age is :".$this->age; 
    } 
    
} 
 
$p1 = new Person("haha", 20); 
$p2 = clone $p1; 
$p2->say(); 
*/  
class Person {  
    private $name;  
    private $age;  
  
    function __construct($name, $age) {  
        $this->name = $name;  
        $this->age = $age;  
    }  
  
    function say() {  
        echo "my name is :".$this->name."<br/>";  
        echo " my age is :".$this->age."<br />";  
    }  
    function __clone() {  
        $this->name = "my is error ".$this->name;  
        $this->age = 30;  
    }  
}  
  
$p1 = new Person("haha", 20);  
$p1->say();  
$p2 = clone $p1;  
$p2->say();  

      

------------------------------------------------------------------

16.對象比較

(==)  如果兩個對象的屬性和屬性值 都相等,而且兩個對象是同一個類的執行個體,那麼這兩個對象變量相等。

(===),這兩個對象變量一定要指向某個類的同一個執行個體(即同一個對象)。

執行個體1

class A{  
      
      $a=new A;  
      $b=new A;   
       if($a==$b){  
          echo "true";  
       }else{  
          echo "false";  
       }  
      $c=new A;  
      $d=&$c;  
          if($c===$d){  
          echo "true";  
       }else{  
          echo "false";  
       }  
      
    }  
      
    執行個體2  
    function bool2str($bool)  
    {  
        if ($bool === false) {  
            return 'FALSE';  
        } else {  
            return 'TRUE';  
        }  
    }  
      
    function compareObjects(&$o1, &$o2)  
    {  
        echo 'o1 == o2 : ' . bool2str($o1 == $o2) . "\n";  
        echo 'o1 != o2 : ' . bool2str($o1 != $o2) . "\n";  
        echo 'o1 === o2 : ' . bool2str($o1 === $o2) . "\n";  
        echo 'o1 !== o2 : ' . bool2str($o1 !== $o2) . "\n";  
    }  
      
    class Flag  
    {  
        public $flag;  
      
        function Flag($flag = true) {  
            $this->flag = $flag;  
        }  
    }  
      
    class OtherFlag  
    {  
        public $flag;  
      
        function OtherFlag($flag = true) {  
            $this->flag = $flag;  
        }  
    }  
      
    $o = new Flag();  
    $p = new Flag();  
    $q = $o;  
    $r = new OtherFlag();  
      
    echo "Two instances of the same class\n";  
    compareObjects($o, $p);  
      
    echo "\nTwo references to the same instance\n";  
    compareObjects($o, $q);  
      
    echo "\nInstances of two different classes\n";  
    compareObjects($o, $r);        

-----------------------------------------

17.對象和引用

  引用:php的引用是别名,就是兩個不同的變量名字指向相同的内容

class A {  
    public $foo = 1;  
}    
  
$a = new A;  
$b = $a;     // $a ,$b都是同一個辨別符的拷貝  
             // ($a) = ($b) = <id>      
$b->foo = 2;  
echo $a->foo."\n";  
  
  
$c = new A;  
$d = &$c;    // $c ,$d是引用  
             // ($c,$d) = <id>  
  
$d->foo = 2;  
echo $c->foo."\n";  
  
  
$e = new A;  
  
function foo($obj) {  
    // ($obj) = ($e) = <id>  
    $obj->foo = 2;  
}  
  
foo($e);  
echo $e->foo."\n";       

-------------------------------------------------------------------------------

對象序列化

序列化對象 - 在會話中存放對象

所有php裡面的值都可以使用函數serialize()來傳回一個包含位元組流的字元串來表示。

unserialize()函數能夠重新把字元串變回php原來的值。

序列化一個對象将會儲存對象的所有變量,但是不會儲存對象的方法,隻會儲存類的名字。

為了能夠unserialize()一個對象,這個對象的類必須已經定義過。

如果序列化類A的一個對象,将會傳回一個跟類A相關,而且包含了對象所有變量值的字元串。

如果要想在另外一個檔案中解序列化一個對象,這個對象的類必須在解序列化之前定義,可以通過包含一個定義該類的檔案或使用函數spl_autoload_register()來實作

執行個體1:

class A {  
          public $one = 1;  
          
          public function show_one() {  
              echo $this->one;  
          }  
      }  
        
    // page1.php:  
      
      include("classa.inc");  
        
      $a = new A;  
      $s = serialize($a);        

  // 把變量$s儲存起來以便檔案page2.php能夠讀到

  file_put_contents('store', $s);

// page2.php:

  // 要正确了解序列化,必須包含下面一個檔案

  include("classa.inc");

  $s = file_get_contents('store');

  $a = unserialize($s);

  // 現在可以使用對象$a裡面的函數 show_one()

  $a->show_one();

------------------------------------

後期靜态綁定)

     後期綁定“的意思是說,static::不再被解析為定義目前方法所在的類,而是在實際運作時計算的。也可以稱之為”靜态綁定“,因為它可以用于(但不限于)靜态方法的調用

     後期靜态綁定的功能:用于在繼承範圍内引用靜态調用的類。

self:: 的限制

使用self:: 或者 __CLASS__對目前類的靜态引用,取決于定義目前方法所在的類:

<?php  
    class A {  
        public static function who() {  
            echo __CLASS__;  
        }  
        public static function test() {  
            self::who();  
        }  
    }  
      
    class B extends A {  
        public static function who() {  
            echo __CLASS__;  
        }  
    }  
      
    B::test();  
    ?>         

------------------------------------------------------------------------------------------

18.$this關鍵字

          $this 的含義是表示 執行個體化後的 具體對象!

    this的用法:

    1,this是指向對象執行個體的一個指針,self是對類本身的一個引用,parent是對父類的引用。

    1,類的内部使用:如果從類的内部通路不為常量const或者static變量或者方法,那麼就必須使用自引用的$this

    2,在構造函數中 指該構造函數建立新對象

    3,引用$this,代表目前的類,解決變量命名沖突和不确定性問題\

    --------------------------------

class Test{  
     function __call($name,$args){  
      if($name=='add' && count($args)==2){  
       $type='num';  
      }  
      foreach ($args as $key=>$val){  
       if(!is_int($val) || is_float($val)){  
        $type='string';  
       }  
      }  
      $method=$name.ucfirst($type);  
        
      if(method_exists($this,$method)){  
       call_user_func_array(array($this,$method),$args);  
      }  
     }  
     function addNum(){  
      echo $i+$j;  
     }  
     function addString(){  
      echo $i.$j;  
     }  
    }  
    $test = new Test();  
    $test->add(3,5);  
    $test->add(4,'4');        

 * 常量 const

在類裡面定義常量用 const 關鍵字,而不是通常的 define() 函數。

文法: const constant = "value";

例子:

運作該例子輸出:

 中國

 我是中國人

 *

 */

Class Person{  
        // 定義常量  
        const COUNTRY = "china";  
        public function myCountry() {  
            //内部通路常量  
            echo "my is ".self::COUNTRY." person<br />";  
        }  
    }  
    // 輸出常量  
    echo Person::COUNTRY."<br />";  
    // 通路方法  
    $p1 = new Person();  
    $p1 -> myCountry();  
    Person::myCountry();        

--------------------

 * PHP 對象的存儲與傳輸(序列化 serialize 對象)

對象的存儲與傳輸

在實際項目應用中,有些任務在一兩個頁面是無法完成的,由于變量到腳本執行完畢就釋放,我們本頁所生成的對象想在其它頁面使用時便碰到了麻煩。

如果需要将對象及其方法傳遞到我們想使用對象的頁面,比較簡單可行的辦法是将對象序列化後存儲起來或直接傳輸給需要的頁面,另一種辦法是将對象注冊為 session 變量。

序列化對象

對象序列化,就是将對象轉換成可以存儲的位元組流。當我們需要把一個對象在網絡中傳輸時或者要把對象寫入檔案或是資料庫時,就需要将對象進行序列化。

序列化完整過程包括兩個步驟:一個是序列化,就是把對象轉化為二進制的字元串,serialize()

函數用于序列化一個對象;另一個是反序列化,就是把對象被序列轉化的二進制字元串再轉化為對象,unserialize()

函數來反序列化一個被序列化的對象。這樣整個過程下來,對象内的類型結構及資料都是完整的。

文法:

string serialize( mixed value )

mixed unserialize( string str [, string callback] )

class Person {  
        private $name;  
        private $age;  
      
        function __construct($name, $age) {  
            $this->name = $name;  
            $this->age = $age;  
        }  
      
        function say() {  
        echo "my name is ".$this->name."<br />";  
        echo " my age is ".$this->age;  
        }  
    }  
      
    $p1 = new Person("haha", 20);  
    $p1_string = serialize($p1);  
      
    //将對象序列化後寫入檔案  
    $fh = fopen("p1.text", "w");  
    fwrite($fh, $p1_string);  
    fclose($fh);        

--------------

<?php

 * PHP面向對象之this 關鍵字

1,PHP5中為解決變量的命名沖突和不确定性問題,引入關鍵字“$this”代表其所在目前對象。

2,$this在構造函數中指該構造函數所建立的新對象。

3,在類中使用目前對象的屬性和方法,必須使用$this->取值。方法内的局部變量,不屬于對象,不使用$this關鍵字取值。

局部變量和全局變量與 $this 關鍵字

4,使用目前對象的屬性必須使用$this關鍵字。

局部變量的隻在目前對象的方法内有效,是以直接使用。

注意:局部變量和屬性可以同名,但用法不一樣。在使用中,要盡量避免這樣使用,以免混淆。

1234567891011121314 <!-- 驗證屬性和局部變量使用方法的類 --> 

<?php   
    class A{       
        private $a = 99;     //這裡寫一個列印參數的方法.       
        public function printInt($a){           
            echo "這裡的 \$a 是傳遞的參數 $a ";           
            echo "<br>";           
            echo "這裡的 \$this->a 是屬性 $this->a";       
        }   
    }   
     $a = new A(); // 這裡的$a 可不是類中的任何一個變量了.   
     $a->printInt(88);  
    ?>         

運作結果:

12 這裡的 $a 是傳遞的參數 88 這裡的 $this->a 是屬性 99

用$this調用對象中的其它方法

1234567891011121314151617 <!--寫一個類,讓他自動完成最大值的換算.-->

<?php   
    class Math{     //兩個數值比較大小.       
        public function Max($a,$b){           
            return $a>$b?$a:$b;       
        }     //三個數值比較大小.       
        public function Max3($a,$b,$c){         //調用類中的其它方法.          
             $a = $this->Max($a,$b);           
            return $this->Max($a,$c);       
        }  
    }   
    $math = new Math();   
    echo "最大值是 ".$math->Max3(99,100,88);   
    ?>         

1 最大值是 100

使用$this調用構造函數

調用構造函數和析構函數的方法一緻。

12345678910111213141516 

<? class A{       
    private $a = 0;       
    public function __construct(){           
    $this->a = $this->a + 1 ;       
    }         
    public function doSomeThing(){           
    $this->__construct();           
    return $this->a;       
    }        
    }   
    $a = new A();   
    // 這裡的$a 可不是類中的任何一個變量了.   
    echo "現在 \$a 的值是" . $a->doSomeThing();   
    ?>        

1 現在 $a 的值是2

$this 到底指的什麼?

$this 就是指目前對象,我們甚至可以傳回這個對象使用 $this

12345678910111213

<?php class A{       
    public function  getASelf(){           
    return $this;       
    }       
    public function __toString(){           
    return "這是類A的執行個體.";       
    }   
    }   
    $a = new A();   
    // 建立A的執行個體;   
    $b = $a->getASelf();   
    //調用方法傳回目前執行個體.   
    echo $a;   
    //列印對象會調用它的__toString方法.   
    ?>         

程式運作結果:

1 這是類A的執行個體.

通過 $this 傳遞對象

在這個例子中,我們寫一個根據不同的年齡發不同工資的類.

我們設定處理年齡和工資的業務模型為一個獨立的類.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

<?php   
    class User{       
    private $age ;       
    private $sal ;       
    private $payoff ;   
    //聲明全局屬性.         
    //構造函數,中建立Payoff的對象.       
    public function __construct(){           
    $this->payoff = new Payoff();       
    }       
    public function getAge(){           
    return $this->age;       
    }       
    public function setAge($age){           
    $this->age = $age;       
    }       
    // 獲得工資.       
    public  function getSal(){           
    $this->sal =    
    $this->payoff->figure($this);           
    return $this->sal;       
    }   
    }   
    //這是對應工資與年齡關系的類.   
    class Payoff{       
    public function figure($a){           
    $sal =0;           
    $age = $a->getAge();           
    if($age >80 || $age <16 ){               
    $sal = 0;           
    }elseif ($age > 50){               
    $sal = 1000;           
    }else{               
    $sal = 800;           
    }           
    return $sal;       
    } }   
    //執行個體化User   
    $user = new User();     
    $user->setAge(55);   
    echo $user->getAge()."age ,his sal is " . $user->getSal(); echo "<br>";     
    $user->setAge(20);   
    echo $user->getAge()."age , his sal is " . $user->getSal(); echo "<br>";     
    $user->setAge(-20); echo $user->getAge()."age , his sal is " . $user->getSal(); echo "<br>";    
    $user->setAge(150); echo $user->getAge()."age , his sal is " . $user->getSal();   
    ?>         

運作結果:

1234 55age ,his sal is 1000 20age , his sal is 800 -20age , his sal is 0 150age , his sal is 0.

**/