PHP類和對象

jopen 12年前發布 | 25K 次閱讀 PHP PHP開發

1、定義和創建類和對象:

定義類要使用class關鍵字。例如:class 類名{//屬性和方法}

創建對象使用new關鍵字。例如: $p1 = new 類名;,可以基于一個類創建多個對象。

2、 類屬性值

(1) 在類中除了聲明屬性外,也可以為屬性賦值,但是只能以如下幾種形式給屬性指定常量值:

示例1:
    public $last_visitor = 'Donnan';    //正確
    public $last_visitor = 9;    //正確
    public $last_visitor = array('Jesse');    //正確
    public $last_visitor = pick_visitor();    //錯誤
    public $last_visitor = 'Chris'.'9';    //錯誤
(2)在類中的方法為變量指定一個非常量值:
    示例2:
    class guest_book{
        public $last_visitor;

        public function update($comment, $visitor){
            if(!empty($comments)){
                array_unshift($this->comments, $comments);
                $this->last_visitor = $visitor;    //在類中的方法為變量指定一個非常量值
            }
        }
    }
(3)在創建對象的過程中為變量指定非常量值,即在類的構造器中進行賦值。
    構造器指的是在創建新對象時自動調用的一個方法,而其名字為__construct()
    示例3:
    class guset_book{
        public $comments;
        public $last_visitor;

        public function __consturct($user){
            $dbh = mysqli_connect('localhost', 'username', 'password', 'site');
            $user = mysqli_real_escape_string($dbh, $user);
            $sql = "select comments, last_visitor from guest_book where user ='$user'";
            $r = mysqli_query($dbh, $sql);

            if($obj = mysqli_fetch_object($dbh, $r)){
                $this->comments = $obj->comments;    //為變量指定非常量值
                $this->last_visitor = $obj->last_visitor;    //為變量指定非常量值
            }
        }            
    }

    $gb = new guest_book('stewart');    //為變量指定非常量值

3、繼承與覆蓋

(1) 通過繼承來擴展一個現存的類,使用關鍵字extends:

class 類名 extends 父類名{}
(2)覆蓋父類方法:
    示例4:
class DB{
    function getResult(){
        return $this->result;
    }

    function query($sql){
        error_log("queryy() must bue overridden by a database-specific child");
        return false;
    }
}

class MySQL extends DB{    // //    MySQL類從父類DB繼承了getResult()方法,但是重新實現了自己特定的MySQL方法query()
    function query($sql){   
        $this->result = mysql_query($sql);
    }
}

(3)在方法名前面前置parent::用以明確地調用一個父類的方法:
    示例5:
fuction escape($sql){
    $safe_sql = mysql_real_escape_string($sql); 
    $safe_sql = parent::escape($safe_sql);    // parent method adds '' around $dql;
    return $safe_sql;
}

(4)注意:當子類中的方法覆蓋了父類中的方法時,除非明確地引用(parent::),否則不會自動調用父類的方法。

4、對象解構器

(1)是一個當對象被銷毀時調用的方法即讓PHP在對象被刪除之前調用的一個方法。方法名__destruct()
    示例6:
class Car{
    function __destruct(){
        //...
    }
}

(2)應用:斷開與數據庫的連接,保存數據庫內容,向遠程服務器發送ping命令。
(3)注意:與構造器不同,不能想結構器傳遞參數,因為你無法確定它會在何時被調用;不能假設PHP會按照某一種特定的次序來逐一銷毀對象,故不能在結構器中引用另一個對象--因為PHP可能已經把那個對象刪除了。
(4)當腳本停止執行時對象會自動被銷毀。要強制銷毀一個對象,可以使用unset()函數:
    $car = new Car;  
    //..; 
    unset($car);

5、訪問控制:

(1)訪問控制即為方法和屬性指定可見性,使用public,protected,private關鍵字。
(2)關鍵字介紹:
    public:公共,用public聲明一個方法或屬性,任何人都可以調用和修改它。
    protected:受保護,被protected修飾的方法或屬性,只有當前類及擴展了當前類的子類中才可以訪問他們。
    private:私有,以private聲明的方法或屬性,只能在當前類中才能訪問。
(3)示例:
    示例7:
class Person{
    public $name;
    protected $age;
    private $salary;

    public function __construct(){//..}

    protected function  set_age(){//...}

    private function set_salary(){//...}
}

6、防止修改類和方法:

(1)關鍵字:final
(2)作用:防止其他開發者重新定義一個子類中的特殊方法,或者在子類化過程重新定義正類。
(3)用final聲明一個方法的原因:
    I:如果有人覆蓋這個方法,就會面臨現實的風險。
    II:這個方法很完美,已經無法再改進了。
(4)用final修飾的類即終類,一個終類是不能被子類化的。終類與都是終方法的類的不同是,后者是可以擴展的(即被繼承),并且雖然不能修改任何一個已經存在的方法,但能夠添加額外方法。
(5)示例:
    示例8:
    final public function connect($server, $username, $password){//...}

    final class MySQL{//...}

7、定義字符串化的對象

(1)介紹:PHP為對象提供了一種控制他們如何轉換為字符串的方法,這樣可以使我們不用寫很多代碼就能夠以一種友好的方式輸出一個對象。

(2)示例:
示例9:
class Car{
    public $type;
    public $brand;
    protected $price;

    function setPrice($price){
        $this->price = $price;
    }

    function setBrand($brand){
        $this->brand = $brand;
    }

    function setType($type){
        $this->type = $type;
    }

    function __toString(){
        return "$this->brand, $this->type, $this->price";
    }
}

$car = new Car;
$car->setPrice('市場價:16.00 至 31.18萬元');
$car->setType('小型');
$car->setBrand('奧迪');
print $car;

(3)輸出:奧迪, 小型, 市場價:16.00 至 31.18萬元

(4)注意:如果你感覺到自己可能會通過__toString()方法返回一個非字符串值的話,可以考慮明確對返回值進行轉換,如上面例子中的
function __toString(){
        return "$this->brand, $this->type,".(string)  $this->price;
    }
(5)直接調用__toString()
    print htmlentities($car->__toString());

8、接口

(1)定義接口使用關鍵字interface。在接口的內部,只需要定義方法的原型,而不用實現這些方法。
    示例10:
interface Nameable{
    public function getName();
    public function setName($name);
}
(2)實現接口:
    如果一個類實現了一個接口的所以方法,就可以說它實現這個接口,如果未能實現接口中定義的所以方法,或者以不同的原型實現了這些方法,會導致PHP報出致命錯誤。
    一個類可以實現任意多個接口。
(3)實現接口示例:
    示例11:
class Book implements Nameable{
     public $name;

    public function getName(){
        return $this->name;
    }

    public function setName($name){
        $this->name = $name;
    }
}

(4)如何檢查一個類是否實現了某一接口?
    有兩種方式:
    方式一:
    示例12:
    class Book implements Nameable{//...}

    $interface = class_implements("Book");
    if(isset($interface['Nameable'])){
        print "Book implements Nameable \n";     //輸出:Book implements Nameable
    }

    方式二:
    示例13:
    class Book implements Nameable{//...}

    $rc = new ReflectionClass('Book');
    if($rc->implementsInterface('Nameable')){
        print "Book implements Nameable \n";     //輸出:Book implements Nameable 
    }

9、抽象類

(1)定義:在類的定義前添加abstract關鍵字就是可以定義一個抽象類,同時,抽象類中必須要定義至少一個抽象方法。在方法定義的前面添加abstract關鍵字就是定義抽象方法。
(2)抽象方法有兩個必要條件:
    抽象方法不能定義為私有方法,因為它們需要被繼承。
    抽象方法不能定義為最終方法,因為他們需要被覆蓋。
(3)注意:如果一個類中包涵了一個抽象方法,那么這個類必須聲明為抽象類;抽象類可以包含非抽象方法。
(4)應用:抽象類最適用于一系列涉及“是什么”關系的對象。這樣就可以使得它們都從一個公共的父類衍生下來具有邏輯上的意義。區別在于子類是實際的類,而父類是抽象的類。
(5)示例14:
abstract class DataBase{
    abstract public function connect();
    abstract public function query();
    abstract public function fetch();
    abstract public function close();
}

class MySQL extends DataBase{
    protected $dbh;
    protected $query;

    public function connect($server,$username, $password, $database){
        $this->dbh = mysql_connect($server, $username, $password, $database);
    }

    public function query($sql){
        $this->query = mysqli_query($this->dbh, $sql);
    }

    public function fetch(){
        return mysqli_fetch_row($this->dbh, $this->query);
    }

    public function close(){
        mysqli_close($this->dbh);
    }

}

10、傳遞對象引用

(1)傳遞對象引用:就是用“=”把一個對象的引用賦給一個變量,以便在更新一個對象時,同時更新另一個。
(2)實質:在使用“=”進行對象賦值時,并沒有創建該對象的一個副本,而是傳遞了一個對該對象的引用。所以,修改一個也就同時修改了另一個。這與php5處理其他類型變量的方式不同,對其他類型的變量傳遞的則是值的副本。也不同與php4,在php4中所有的變量都是傳遞值的副本。所以,在PHP4中需要使用“=&”來使兩個對象建立鏈接,而現在只需要使用“=”就可以。
(3)示例15:
$car = new Car;
$car->setPrice('市場價:16.00 至 31.18萬元');
$car->setType('小型');
$car->setBrand('奧迪');

$audi = $car;    //現在$audi和$car實際上就是一個對象的兩個名稱

11、克隆對象與聚合類

(1)克隆對象方案:用“=”實現通過引用來拷貝對象,要拷貝對象的值,要使用clone。
(2)clone關鍵字克隆對象的實質:使用clone關鍵字克隆的過程中會把一個對象中所有的屬性都拷貝到第二個對象中。其中也包括屬性中保存的對象,所以克隆的對象不會與原始對象共享一個引用,即改變克隆的對象的屬性值不會影響到原來對象的屬性值。
(3)聚合類:所謂聚合類是指在類中以某種方式嵌入了其他的類,使得不論訪問原始的類,還是嵌入的類都很方便。
(4)示例16:

class Address{
    protected $city;
    protected $country;

    public function setCity($city){
        $this->city = $city;
    }

    public function getCity(){
        return $this->city;
    }

    public function setCountry($country){
        $this->country = $country;
    }

    public function getCountry(){
        return $this->country;
    }
}

class Person{
    protected $name;
    protected $address;//Person 有一個 Address

    public function __construct(){
        $this->address = new Address;
    }

    public function setName($name){
        $this->name = $name;
    }

    public function getName(){
        return $this->name;
    }

    public function __call($method, $arguments){
        if(method_exists($this->address, $method)){
            return call_user_func_array(array($this->address, $method), $arguments);
        }
    }
}

$rasmus = new Person;
$rasmus->setName('Rasmus Lerdorf');
$rasmus->setcity('Sunnyvale');

$zeev = clone $rasmus;
$zeev->setName("Zeev Surask");
$zeev->setCity('Tel Aviv');

print $rasmus->getName()." live in ".$rasmus->getCity();
echo "\n";
print $zeev->getName().' live in '.$zeev->getCity();
echo "\n";

輸出結果:
Rasmus Lerdorf live in Tel Aviv
Zeev Surask live in Tel Aviv

(5)上方示例的問題:zeev對象調用setName()時沒有問題,而當調用getCity()反而結果出現了問題,這是因為$name屬性是一個字符串,它在傳遞時拷貝的是只,但是$address是一個對象,而對象拷貝的是引用,這種形式的對象克隆成為“淺克隆”,或者“淺拷貝。相對的“深克隆”指的是克隆所有有關對象讀克隆。要在php5中控制克隆對象,是通過在相應類中實現一個__clone()方法來實現的。在__clone()方法的內部會有一個保存$this變量中的淺拷貝來表示PHP沒有 __clone()方法時提供的對象。因為PHP已經拷貝了所有屬性,所以只需要覆蓋不需要的屬性即可。在Person類中,$name是沒有問題的,只有$address需要明確地克隆。在上面Person類的最后加上一下代碼:
public function __clone(){
        //需要明確的克隆的屬性
        $this->address = clone $this->address;
    }

之后輸出:
Rasmus Lerdorf live in Sunnyvale
Zeev Surask live in Tel Aviv

(6)關于__clone()方法:
    使用clone操作符克隆保存在屬性中的對象,會導致PHP檢測這些對象中是否包含__clone()方法,如果包含一個,PHP就會調用它。而且,即使對于嵌套在更深層中的對象也會重復這樣檢查。這一過程保證了正確地克隆完整的對象,別且也證明了它為什么被稱為深度克隆。

12、調用由另一個方法返回對象的方法

如果你想要調用由另一個方法返回的對象的方法,直接在地一個方法后面調用第二個方法,如:
    $organge = $fruit->get('citrus')->peel();
這是在php4基礎上的一個改進措施。在php4中,要實現同樣的功能需要使用一個臨時的變量。
      $organge = $fruit->get('citrus');
      $organge->peel();

13、聚合對象

(1)理解:你想把兩個或多個對象組合在一起,使結果就像是一個對象
(2)聚合對象并用__call()方法截獲對方法的調用。
    __call()方法會捕捉到任何對未在類中定義的方法的調用。在調用這方法時,需要傳遞兩參數,一個是方法名,另一個是保存著要傳遞給方法的參數的數組$arguments。
    檢測是通過使用method_exists()方法并為其提供兩個參數,第一個參數是對象,第二個參數是方法名來進行的。如果檢測結果返回true,也就是說調用的方法是有效的,那么可以調用它。
    call_user_func_array()方法是用來解決傳遞給方法的參數數組$argumentsde ,這個函數可以讓我們調用一個用戶函數,并且在數組中傳遞參數。傳遞給它的地一個參數是你的函數名,第二個參數是數組參。但是,在這里我們想要調用的是對象的一個方法而非是一個函數,有一種特殊的語法可以用于這種情況,即不傳遞函數名,而是代之以傳遞一個包含兩個元素的數組,這個數組中第一個元素是對象,另一個元素是要被調用的方法名。這樣就可以通過call_user_func_array()調用這個對象的方法了,之后必須將call_user_func_array()的結果返回給原始的調用程序,要不然返回的值就會悄無聲息地廢棄掉。
(3)示例如示例16

14、類常量與全局常量的定義和使用

示例17:

define('pi', 10);//全局pi常量,本質上是final屬性

class Circle{
    const pi = 3.1415926;//類中的pi常量
    protected $radius;

    public function __construct($radius){
        $this->radius = $radius;
    }

    public function circumference(){
        return 2 * pi * $this->radius;//全局pi常量
    }
    public function circumference2(){
        return 2 * self::pi * $this->radius;//類中的pi常量
    }
}

$c = new Circle(1);
print $c->circumference();     //輸出:20
echo "\n";
print $c->circumference2();     //輸出:6.2831852
echo "\n";

15、靜態屬性和方法:

示例18:

/*定義靜態屬性和方法
*調用靜態方法通過類名和::來調用,不能在靜態方法中使用$this變量
*調用靜態屬性通過self::$屬性名,
*/
class Format{
    public static function number($number, $decimals = 2, $decimal = '.', $thousands = ','){
        return number_format($number, $decimals, $decimal, $thousands);
    }
}

print Format::number(1234.567);    //調用靜態方法

class Database{
    private static $dbh = NULL;

    public function __construct($server, $username, $password){
        if(self::$dbh == NULL){    //調用靜態屬性
            self::$dbh = db_connect($server, $username, $password)
        }else{
            self::$dbh = self::$dbh ;
        }
    }
}

16、控制對象的序列化

示例19:
class LogFile{
    protected $filename;
    protected $handle;

    public function __construct($filename){
        $this->$filename = $filename;
        $this->open();
    }

    private function open(){
        $this->handle = fopen($this->filename, 'a');
    }

    public function __destruct($filename){
        fclose($this->handle);
    }

    //當對象序列化調用時調用,返回一個可序列化的對象屬性的數組
    public function __sleep(){
        return array('filename');
    }

    //當對象飯序列化時調用
    public function __wakeup(){
        $this->open();
    }
}

17、分析對象

(1)方法:使用反射(Reflection)類來查明對象的信息
(2)示例20:

class Person{
    public $name;
    protected $spouse;
    private $password;

    public function __construct($name){
        $this->name = $name;
    }

    public function getName(){
        return $this->name;
    }

    public function setSpouse(Person $spouse){
        if(!isset($this->spouse)){
            $this->spouse = $spouse;
        }
    }

    public function setPassword($password){
        $this->password = $password;
    }
}

Reflection::export(new ReflectionClass('Person'));

運行結果:
Class [ <user> class Person ] {
  @@ /home/suiyc/workspace/sycPro/class/Reflection.php 2-24

  - Constants [0] {
  }

  - Static properties [0] {
  }

  - Static methods [0] {
  }

  - Properties [3] {
    Property [ <default> public $name ]
    Property [ <default> protected $spouse ]
    Property [ <default> private $password ]
  }

  - Methods [4] {
    Method [ <user, ctor> public method __construct ] {
      @@ /home/suiyc/workspace/sycPro/class/Reflection.php 7 - 9

      - Parameters [1] {
        Parameter #0 [ <required> $name ]
      }
    }

    Method [ <user> public method getName ] {
      @@ /home/suiyc/workspace/sycPro/class/Reflection.php 11 - 13
    }

    Method [ <user> public method setSpouse ] {
      @@ /home/suiyc/workspace/sycPro/class/Reflection.php 15 - 19

      - Parameters [1] {
        Parameter #0 [ <required> Person $spouse ]
      }
    }

    Method [ <user> public method setPassword ] {
      @@ /home/suiyc/workspace/sycPro/class/Reflection.php 21 - 23

      - Parameters [1] {
        Parameter #0 [ <required> $password ]
      }
    }
  }
}

18、檢查某對象是不是一個特定類的對象

(1)關鍵字:instanceof
(2) 示例21:
if($car instanceof Car){
    print " car is the instance of class Car! \n";
}else{
    print " car is not the instance of class Car! \n";
}
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!