如果你曾經寫過一串「先宣告資料、再呼叫函式、最後祈禱不要改壞其他地方」的 PHP,歡迎來到物件導向的世界。這裡會把資料和相關行為放在一起,讓程式不必像咖啡店的桌面一樣,什麼東西都堆在同一區。
這篇會用簡單的 PHP 範例帶你理解類別(Class)、物件(Object)、屬性、方法、$this 與 new,也會說明封裝和物件之間的組合。讀完後,你應該能看懂基本的 OOP 程式,並開始自己設計小型類別。
為什麼要學 PHP 物件導向
物件導向程式設計(Object-Oriented Programming,OOP)不是把每個變數都改名成物件,也不是看到 class 就要立刻召開架構會議。它是一種組織程式的方式:把相關的資料和操作資料的程式碼放在同一個類別裡。
這樣做有幾個實際好處:
- 更容易組織:一個類別可以集中描述某種事物的資料與行為。
- 減少重複:同一個類別可以建立多個物件,不必複製一整套程式碼。
- 比較容易維護:需求改變時,通常可以先從相關類別下手,不必在整個專案裡玩尋寶。
- 方便協作:大型專案可以依照責任拆分不同類別,讓程式碼邊界更清楚。
- 支援封裝:可以限制外部直接修改資料的方式,降低資料被亂改的機會。
OOP 不會自動讓所有程式變漂亮;類別設計得不好,仍然可能長成一團義大利麵,只是現在義大利麵住進了 class 裡。
類別與物件是什麼
先用一個生活化的比喻:類別像設計圖,物件像依照設計圖做出來的成品。
例如,Cake 類別可以描述蛋糕有哪些資料(口味、尺寸),以及可以做什麼事(烘烤)。依照這個類別建立出來的巧克力蛋糕和草莓蛋糕,就是兩個不同的物件。
換句話說:
- 類別(Class):定義物件應該有哪些屬性和方法。
- 物件(Object):類別建立出來的實例,擁有自己的資料。
- 實例化(Instantiation):使用
new,依照類別建立物件的過程。
類別本身比較像規格,物件才是程式執行時真正拿來工作的東西。設計圖不能自己吃蛋糕,這點 PHP 也沒有打算替它開例外。
用 PHP 建立第一個類別
類別包含屬性與方法
以下建立一個簡單的 Cake 類別:
<?php
class Cake
{
public $flavor;
public $size;
public function bake()
{
echo '正在烘烤 ' . $this->flavor . ' 口味的蛋糕。';
}
}
這段程式有兩種成員:
flavor和size是屬性(Property),用來保存物件的資料。bake()是方法(Method),用來描述物件可以執行的行為。
方法裡的 $this 代表「目前正在呼叫這個方法的物件」。因此,$this->flavor 讀取的是目前這個蛋糕自己的口味,而不是某個神秘的全域蛋糕。
使用 new 建立物件
有了類別之後,可以用 new 建立物件,再設定它的屬性:
$chocolateCake = new Cake();
$chocolateCake->flavor = '巧克力';
$chocolateCake->size = '大';
$chocolateCake->bake();$chocolateCake 是 Cake 的一個物件。箭頭運算子 -> 用來存取物件的屬性或方法,所以:
$chocolateCake->flavor代表這個物件的flavor屬性。$chocolateCake->bake()代表呼叫這個物件的bake()方法。
同一個類別也能建立多個彼此獨立的物件:
$chocolateCake = new Cake();
$chocolateCake->flavor = '巧克力';
$strawberryCake = new Cake();
$strawberryCake->flavor = '草莓';
$chocolateCake->bake();
$strawberryCake->bake();兩個物件都來自 Cake 類別,但各自保存不同的 flavor。類別像食譜,物件則是不同口味的成品;PHP 沒有規定所有蛋糕都得是巧克力,算是對甜點界的基本尊重。
用類別管理書籍
接著把概念放進一個比較完整的例子。假設我們要描述一本書,可以把書名和作者放進屬性,再提供一個方法顯示書籍資訊:
class Book
{
public $title;
public $author;
public function describe()
{
return $this->title . ',作者:' . $this->author;
}
}建立物件並使用它:
$book = new Book();
$book->title = '哈比人';
$book->author = 'J. R. R. 托爾金';
echo $book->describe();這裡的 Book 是類別,$book 是物件。describe() 不需要另外接收 $book,因為它透過 $this 就能取得目前物件的資料。
把多個物件放在一起
物件也可以成為另一個物件的資料。像書架可以保存多本 Book:
class Bookshelf
{
public $books = [];
public function addBook(Book $book)
{
$this->books[] = $book;
}
public function listBooks()
{
foreach ($this->books as $book) {
echo $book->describe() . PHP_EOL;
}
}
}使用 Bookshelf:
$firstBook = new Book();
$firstBook->title = '哈比人';
$firstBook->author = 'J. R. R. 托爾金';
$secondBook = new Book();
$secondBook->title = '傲慢與偏見';
$secondBook->author = '珍・奧斯汀';
$bookshelf = new Bookshelf();
$bookshelf->addBook($firstBook);
$bookshelf->addBook($secondBook);
$bookshelf->listBooks();Bookshelf 的 books 屬性是一個陣列,裡面放著多個 Book 物件。這種「一個物件管理其他物件」的做法,就是物件組合(composition)的簡單例子。
封裝與可見性
前面的屬性使用 public,代表類別外部也能直接讀寫。這對示範很方便,但在實際程式裡,未必希望任何地方都能隨意修改資料。
PHP 提供三種常見的可見性:
public:類別內外都可以存取。protected:類別本身和繼承它的子類別可以存取。private:只有宣告該成員的類別本身可以存取。
例如,把書名設為私有,並透過方法控制修改方式:
class Book
{
private $title;
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
}
$book = new Book();
$book->setTitle('哈比人');
echo $book->getTitle();這就是封裝(Encapsulation):把資料和操作資料的方法放在一起,並限制外部直接碰觸內部狀態的方式。日後如果需要檢查書名是否為空白,可以在 setTitle() 裡加入規則,而不必搜尋整個專案的每一個賦值動作。
這篇的重點整理
到這裡,你已經掌握 PHP OOP 的基本詞彙:
- 類別是建立物件的定義,描述屬性與方法。
- 物件是類別的實例,保存自己的資料。
- 屬性代表物件的狀態,例如書名或作者。
- 方法代表物件的行為,例如列出書籍資訊。
new用來依照類別建立物件。$this在物件方法中代表目前的物件。- 封裝透過可見性與方法,控制資料如何被使用。
- 物件組合可以讓一個物件管理其他物件,例如書架管理書籍。
當你開始看到程式裡有許多互相關聯的資料和函式時,可以問自己:「這些東西是不是其實屬於同一種事物?」如果答案是,那就可能是設計類別的好時機。先把責任分清楚,再來喝咖啡;不然最後連咖啡都要被迫繼承 Everything 類別。
參考資料
- PHP 官方文件:Classes and Objects:查閱 PHP 類別與物件的完整說明。
- PHP 官方文件:The Basics:了解類別宣告、物件建立與
$this的基本用法。 - PHP 官方文件:Visibility:查閱
public、protected與private的存取規則。 - PHP 官方文件:Properties:了解類別屬性的宣告與物件屬性存取方式。

