1. 程式人生 > >PHP學習筆記(四)--面向物件

PHP學習筆記(四)--面向物件

1、基本內容

注意事項:

  1. 無論是使用“$this->”還是使用“物件名->”格式,後面的變數是沒有$符號的,如$this->value;
  2. 通過“類名::常量”方式類訪問類常量的,如bastBall::Type;
  3. 在PHP中使用“垃圾回收”機制,不需要手動建立解構函式。不再使用的物件會自動清楚,釋放記憶體;
  4. 對於成員方法,如果沒有指定關鍵字,則預設是public,這一點與C++不同;
  5. 被protected修飾的類成員,可以在本類和子類中被呼叫,其它地方不可以,這也與C++不同;
  6. 在靜態方法中,只能呼叫靜態變數,而不能呼叫普通變數,而普通方法中可以呼叫靜態變數;
  7. 在類內部訪問靜態成員使用“self::靜態變數”,在類外部使用“類名::靜態變數”;
  8. 建構函式__construct及解構函式__destruct不能宣告為私有型別;
  9. finale修飾的類不可被再繼承,也不能再有子類。finale修飾的方法不可以進行重寫,也不可以被覆蓋;
  10. 抽象類是一種不能被例項化的類,只能作為其它的父類來使用。抽象類包含變數、成員方法,至少要包含一個抽象方法。抽象類和抽象方法主要用於複雜的層次關係中。
  11. PHP只支援單繼承,要想實現多繼承就要使用介面。介面類中只能包含未實現的方法和一些成員變數。介面中的類成員必須使用public來修飾。介面類中的所有未實現的方法必須要在子類中實現;
  12. 類常量前面不加$符號。

 

【例1】類的定義及使用

<?php

    class SportObject{

       const TYPE='Sports';

       static $counter=0;

       private $name;

       private

$age;

       private $sex;

       public function __construct($name,$age,$sex){

           $this->name=$name;

           $this->age=$age;

           $this->sex=$sex;

           self::$counter++;//計數

       }

       public function __destruct(){

           echo self::TYPE.'呼叫了解構函式';//類中訪問常量使用self

       }

       public function PrintInfo(){

           echo $this->name.',';

           echo $this->age.',';

           echo $this->sex.'<p>';

       }

       public function IsBoy(){

           return $this->sex='' ? true : false;

       }

       public function ShowCounter(){

           echo '總共建立了:'.self::$counter.'個例項';

       }

    }

    $so=new SportObject('張三',22,'');

    $so->PrintInfo();//呼叫成員方法

    echo $so->IsBoy();

    echo SportObject::TYPE;//訪問類的常量

    $sp2=new SportObject('張琴',25, '');

    $sp2->ShowCounter();

?>

2、繼承

【例2】繼承

<?php

    class SportObject{

       protected $name;

       private $age;

       private $sex;

       public function __construct($name,$age,$sex){

           $this->name=$name;

           $this->age=$age;

           $this->sex=$sex;

           self::$counter++;//計數

       }

      

       public function PrintInfo(){

           echo '姓名'.$this->name.'<p>';

       }

      

    }

    class BasketBallSports extends SportObject{

       private $height;

       public function __construct($name, $height){

           $this->name=$name;

           $this->height=$height;

       }

       public function PrintInfo(){//覆蓋父類的方法

           echo '身高:'.$this->height.'<p>';

       }

    }

    $sp1=new BasketBallSports('鄭鈞', 188);

    $sp1->PrintInfo();

?>

 

3、多型

【例3】多型

<?php

    class Overloader

    {

       private $properties = array();

   

       function __get($property_name)

       {

           if(isset($this->properties[$property_name]))

           {

              return($this->properties[$property_name]);

           }

           else

           {

              return(NULL);

           }

       }

   

       function __set($property_name, $value)

       {

           $this->properties[$property_name] = $value;

       }

   

       public function __call($method, $p)

       {

          

           if($method == 'display')

           {

              if(is_object($p[0]))

                  $this->displayObject($p[0]);

              else

                  if(is_array($p[0]))

                     $this->displayArray($p[0]);

                  else

                     $this->displayScalar($p[0]);

           }

       }

   

       public function displayObject($p)

       {

           echo ("你傳入的是個物件,內容如下:<br>");

           print_r($p);

           echo "<hr>";

       }

   

       public function displayArray($p)

       {

           echo ("你傳入的是個陣列,內容如下:<br>");

           print_r($p);

           echo "<hr>";

       }

   

       public function displayScalar($p)

       {

           echo ("你傳入的是個單獨變數,內容如下:<br>" . $p);

           echo "<hr>";

       }

    }

 

    $o = new Overloader();

    //呼叫 __set() 給一個不存在的屬性變數賦值

    $o->dynaProp = "Dynamic Content";

    $o->display('Cat');

?>

 

4、抽象類

【例4】抽象類

<?php

    abstract class CommodityObject{

       protected $type;

       const CNAME='CommodityObject';

       static public function Show(){

          

       }

       public function __construct(){

           $this->type='通用類';

       }

       public function Display(){

           echo $this->type;

       }

       abstract function service($getName,$price,$num);

    }

    class MyBooks extends CommodityObject{

       function service($getName, $price, $num){

           echo '書名:'.$getName.'<p>';

           echo '價格:'.$price.'<p>';

           echo '數量:'.$num.'<p>';

       }

    }

    $book=new MyBooks();$book->service('PHP從入門到精通', 60, 3);

    $book->Display();

?>

 

5、介面

【例5】介面

<?php

    interface MPopedom{

       function popedom();

    }

    interface MPurview{

       function purview($name);

    }

    class Manager implements MPopedom,MPurview{

       function popedom(){

           echo '擁有會員的許可權';

       }

       function purview($name){

           echo '擁有管理員的許可權';

       }

    }

    $manager=new Manager();

    $manager->popedom();

    $manager->purview('張三');

?>

 

 

6、克隆物件

使用close關鍵字進行物件的複製,直接將一個物件賦值給另一個物件$object2=$object1,則object2是object1的引用。有時候單純的克隆物件外,還需要克隆出來的物件可以擁有自己的屬性和方法,這時可以使用__clone()方法來實現,在物件的克隆過程中呼叫該方法。

<?php

    class SpoerObject{

       private $object_type='book';

       public function setType($type){

           $this->object_type=$type;

       }

       public function getType(){

           return $this->object_type;

       }

    }

    $book1=new SpoerObject();

    $book2=$book1;

    $book2->setType('computer');

    echo $book1->getType();//輸出computer

    $book3=clone $book1;

    $book3->setType('mouse');

    echo $book1->getType();//還是輸出computer

?>

 

<?php

    class SpoerObject{

       private $object_type='book';

       public function setType($type){

           $this->object_type=$type;

       }

       public function getType(){

           return $this->object_type;

       }

       public function __clone(){

           $this->object_type='computer';

       }

    }

    $book1=new SpoerObject();

    $book2=clone $book1;

    echo $book2->getType();//輸出computer

   

?>

 

7、物件比較及型別檢測

使用“==”可以比較兩個物件的內容是否相同,“===”可以比較兩個物件的地址是否相同。

instanceof操作符可以檢測當前物件是屬於哪個類。一般格式為:

ObjectName instanceof ClassName

【例1】物件型別的比較

<?php

    class SpoerObject{

       private $object_type='book';

       public function setType($type){

           $this->object_type=$type;

       }

       public function getType(){

           return $this->object_type;

       }

    }

    $book1=new SpoerObject();

    $book2=$book1;

    $book3=clone $book1;

    echo ($book2==$book1 ? "true" : "false").'<p>';//true

    echo ($book2===$book1 ? "true" : "false").'<p>';//true

    echo ($book3==$book1 ? "true" : "false").'<p>';//true

    echo ($book3===$book1 ? "true" : "false").'<p>';//false

?>

 

【例2】

<?php

    class SportObject{   }//建立空類

    class BasketBallSports extends SportObject{

       private $height;

       public function __construct($height){

           $this->height=$height;

       }

       public function PrintInfo(){//覆蓋父類的方法

           echo '身高:'.$this->height.'<p>';

       }

    }

    $sp1=new BasketBallSports( 188);

    echo ($sp1 instanceof BasketBallSports ? 'true' : 'false');//true

    echo ($sp1 instanceof SportObject ? 'true' : 'false');//true

?>

 

8、魔術方法

PHP中以兩個下劃線“__”開頭的方法,例如__destruct、__construct、__clone等都稱為魔術方法。如果要呼叫這些魔術方法必須在類中進行定義。

  1. __set()方法

當程式試圖寫入一個不存在或不可見的成員變數時,PHP會呼叫__set()方法。__set()包含兩個引數,分別是變數名稱和變數值,引數都不可省略。

 

  1. __get()方法

當程式呼叫一個未定義或不可見的成員變數時,可以通過__get()方法來讀取變數值。__get()犯法有一個引數,表示要呼叫的變數名。

【例1】

<?php

    class SportObject{

       private $type='';

       public function __get($name){

           if(isset($this->$name)){

              echo "<p>變數".$name."的值為:".$this->$name;

           }else{//如果變數未定義

              echo "<p>變數".$name."未定義,初始化為0";

              $this->$name=0;

           }

       }

       public function __set($name,$value){

           if(isset($this->$name)){

              $this->$name=$value;

              echo '<p>變數'.$name.'已定義';

           }else{

              echo '<p>變數'.$name.'未定義,被初始化為'.$value;

              $this->$name;

           }

       }

    }

    $myComputer=new SportObject();

    $myComputer->type='DIY';

    echo $myComputer->type;

    $myComputer->name;

?>

執行結果為:

  1. __call()方法

當程式檢視呼叫不存在或不可見的成員方法時,PHP會先呼叫__call()方法類儲存方法名及其引數。__call()方法包含兩個引數,即方法名和方法引數,其中方法引數是以陣列的形式存在的。

<?php

    class SportObject{

       public function myDream(){

           echo '不存在要 呼叫的方法時呼叫此方法<p>';

       }

       public function __call($method,$parameter){

           echo '方法'.$method.'不存在';

           echo '引數資訊:';

           var_dump($parameter);

           $this->myDream();

       }

    }

    $exam=new SportObject();

    $exam->dream('張三',22);

?>

 

  1. __sleep()方法和__wakeup()方法

PHP使用serialize()函式可以序列化物件。就是將類中的變數全部儲存下來,物件中的類則只儲存類名。當一個物件被序列化,PHP會呼叫__sleep方法(如果存在的話). 在反序列化一個物件後,PHP 會呼叫__wakeup方法. 這兩個方法都不接受引數. __sleep方法必須返回一個數組,包含需要序列化的屬性. PHP會拋棄其它屬性的值. 如果沒有__sleep方法,PHP將儲存所有屬性. 在程式執行前,serialize() 函式會首先檢查是否存在一個魔術方法 __sleep.如果存在,__sleep()方法會先被呼叫,然後才執行序列化(序列化)操作。這個功能可以用於清理物件,並返回一個包含物件中所有變數名稱的陣列。如果該方法不返回任何內容,則NULL被序列化,導致一個E_NOTICE錯誤。與之相反,unserialize()會檢查是否存在一個__wakeup方法。如果存在,則會先呼叫 __wakeup方法,預先準備物件資料。

<?php

    class Connection {

        protected $link;

        private $server, $username, $password, $db;

       

        public function __construct($server, $username, $password, $db)

        {

            $this->server = $server;

            $this->username = $username;

            $this->password = $password;

            $this->db = $db;

            $this->connect();

        }

       

        private function connect()

        {

            $this->link = mysql_connect($this->server, $this->username, $this->password);

            mysql_select_db($this->db, $this->link);

            echo '連線資料庫成功!<p>';

        }

       

        public function __sleep()

        {

            return array('server', 'username', 'password', 'db');

        }

       

        public function __wakeup()

        {

            $this->connect();

        }

       

    }

   

    $cnn = new Connection('localhost', 'root', null, 'students');

    $str=serialize($cnn);

    echo '序列化後的字串'.$str.'<p>';

    $recnn=unserialize($str);

   

?>

 

輸出結果:

 

  1. __toString()方法

當使用echo或print輸出物件時,將物件轉化為字串。如果沒有__toString()方法,直接輸出物件會導致致命錯誤。注意,使用echo或print後面直接跟輸出的物件,不可加入其它的字元。如echo ‘字元’.$myComputer不可以。

<?php

    class Connection {

        protected $link;

        private $server, $username, $password, $db;

       

        public function __construct($server, $username, $password, $db)

        {

            $this->server = $server;

            $this->username = $username;

            $this->password = $password;

            $this->db = $db;

            $this->connect();

        }

       

        private function connect()

        {

            $this->link = mysql_connect($this->server, $this->username, $this->password);

            mysql_select_db($this->db, $this->link);

            echo '連線資料庫成功!<p>';

        }

       public function __toString(){

            $res='伺服器名:'.$this->server.'<p>';

           $res.='使用者名稱:'.$this->username.'<p>';

           $res.='密碼:'.$this->password.'<p>';

           $res.='資料庫:'.$this->db.'<p>';

           return $res;     }

    }

   

    $cnn = new Connection('localhost', 'root', '', 'students');

    echo $cnn;

?>

 

  1. __autoload()方法

 

__autoload()方法可以自動例項化所需要使用的類。__autoload()方法在指定的路勁下自動查詢和該類同名稱的檔案,如果找到程式繼續執行,否則報錯。注意,類名必須與儲存的檔名一致。

現在將上面5)中的類connection儲存在當前工程目錄下的connection.php中,index.php訪問程式碼如下:

<?php

    function __autoload($class_name){

       $cname=getcwd().'\\'.$class_name.'.php';

       if(file_exists($cname)){

       include_once($cname);//動態引入類檔案

    }else{

    echo '類路徑'.$cname.'錯誤';

    }

    }

    $cnn = new Connection('localhost', 'root', '', 'students');

    echo $cnn;

?>