章 18. 類與物件(PHP 4)

類是變量與作用於這些變量的函數的集合。使用下面的語法定義一個類:

<?php
class Cart {
    var 
$items;  // 購物車中的物品

    // 將 $num 個 $artnr 物品加入購物車

    
function add_item($artnr$num) {
        
$this->items[$artnr] += $num;
    }

    
// 將 $num 個 $artnr 物品從購物車中取出

    
function remove_item($artnr$num) {
        if (
$this->items[$artnr] > $num) {
            
$this->items[$artnr] -= $num;
            return 
true;
        } elseif (
$this->items[$artnr] == $num) {
            unset(
$this->items[$artnr]);
            return 
true;
        } else {
            return 
false;
        }
    }
}
?>

上面的例子定義了一個 Cart 類,這個類由購物車中的商品構成的陣列和兩個用於從購物車中增加和移除商品的函陣列成。

警示

不能將一個類的定義分割到多個檔案中。也不能將一個類的定義分割到多個 PHP 塊中,除非該分割是在一個方法聲明內定。以下用法將不起作用:

<?php
class test {
?>
<?php
    
function test() {
        print 
'OK';
    }
}
?>

但是以下用法是可以的:

<?php
class test {
    function 
test() {
        
?>
        <?php
        
print 'OK';
    }
}
?>

以下警示僅用於 PHP 4。

注意

名稱 stdClass 已經被 Zend 使用並保留。不能在 PHP 代碼中定義名為 stdClass 的類。

注意

函數名 __sleep__wakeup 在 PHP 類中是魔術函數。除非想要與之聯繫的魔術功能,否則在任何類中都不能以此命名函數。

注意

PHP 將所有以 __ 開頭的函數名保留為魔術函數。除非想要使用一些見於文件中的魔術功能,否則建議不要在 PHP 中將函數名以 __ 開頭。

在 PHP 4 中,var 變量的值只能起始化為常量。用非常量值起始化變量,需要一個起始化函數,該函數在物件被建立時自動被呼叫。這樣一個函數被稱之為構造函數(見下面)。

<?php
/* PHP 4 中不能這樣用 */
class Cart {
    var 
$todays_date date("Y-m-d");
    var 
$name $firstname;
    var 
$owner 'Fred ' 'Jones';
    
/* 不過包括有常量的陣列可以 */
    
var $items = array("VCR""TV");
}

/* 應該這樣進行 */
class Cart {
    var 
$todays_date;
    var 
$name;
    var 
$owner;
    var 
$items = array("VCR""TV");
    function 
Cart() {
        
$this->todays_date date("Y-m-d");
        
$this->name $GLOBALS['firstname'];
        
/* etc. . . */
    
}
}
?>

類也是一種類型,就是說,它們是實際變量的藍圖。必須用 new 運算符來建立相應類型的變量。

<?php
$cart 
= new Cart;
$cart->add_item("10"1);

$another_cart = new Cart;
$another_cart->add_item("0815"3);
?>

上述代碼建立了兩個 Cart 類的對象 $cart$another_cart,物件 $cart 的方法 add_item() 被呼叫時,增加了 1 件 10 號商品。對於物件 $another_cart,3 件 0815 號商品被新增到購物車中。

$cart$another_cart 都有方法 add_item(),remove_item() 和一個 items 變量。它們都是明顯的函數和變量。可以把它們當作檔案系統中的某些類似目錄的東西來考慮。在檔案系統中,可以擁有兩個不同的 README.TXT 檔案,只要不在相同的目錄中。正如從為了根目錄訪問每個檔案需要輸入該檔案的完整的路徑名一樣,必須指定需要呼叫的函數的完整名稱:在 PHP 術語中,根目錄將是全局名字空間,路徑名符號將是 ->。因而,名稱 $cart->items$another_cart->items 命名了兩個不同的變量。注意變量名為 $cart->items,不是 $cart->$items,那是因為在 PHP 中一個變量名只有一個單獨的美元符號。

<?php
// 正確,只有一個 $
$cart->items = array("10" => 1);

// 不正確,因為 $cart->$items 變成了 $cart->""
$cart->$items = array("10" => 1);

// 正確,但可能不是想要的結果:
// $cart->$myvar 變成了 $cart->items
$myvar 'items';
$cart->$myvar = array("10" => 1);
?>

在定義類的時候,無法得知將使什麼名字的對象來訪問:在編寫 Cart 類時,並不知道之後對象的名稱將會命名為 $cart 或是 $another_cart。因而你不能在類中使用 $cart->items。然而為了類定義的內定訪問自身的函數和變量,可以使用偽變量 $this 來達到這個目的。$this 變量可以理解為「我自己的」或是「現用的物件」。因而 '$this->items[$artnr] += $num' 可以理解為「我自己的物品陣列的 $artnr 計數器加 $num」或是「在現用的對象的物品陣列的 $artnr 計數器加 $num」。

注: 偽變量 $this 通常未定義,若果其所在的方法是被靜態呼叫的話。但這不是個嚴格規定:若果一個方法被從另一個物件內靜態呼叫的話,則 $this 會被定義。此時 $this 的值是那個發出呼叫的對象。用下例演示:

<?php
class A
{
    function 
foo()
    {
        if (isset(
$this)) {
            echo 
'$this is defined (';
            echo 
get_class($this);
            echo 
")\n";
        } else {
            echo 
"\$this is not defined.\n";
        }
    }
}

class 
B
{
    function 
bar()
    {
        
A::foo();
    }
}

$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>

上例將輸出:

$this is defined (a)
$this is not defined.
$this is defined (b)
$this is not defined.

注: 有一些不錯的函數用來處理類和對象。應該追蹤一下類/物件函數