本篇會介紹基礎的物件導向 PHP,並提供一些簡單新手向的範例~
Class
宣告一個 class,就可利用此 class 來建立物件:
class demo{
}
$demo = new demo; //以 demo 這個 class 建立一個叫做 $demo 的物件
Member, Property, Function
Members
Class 的成員 (member) 有屬性 (property) 和方法 (method) 兩種,以下都直接以英文稱呼,public 是宣告成員的可視性 (visibility), method 的預設性質都是 public,之後會再對可視性做進一步介紹:
class demo{
//屬性 (property)
public $hello = 'Hello World';
//方法 (method)
function hello(){
}
}
$demo = new demo;
要注意的是,property 不是變數,在下例中會報錯是因為 public $hello
並不是變數,而是 demo 的 property,function hello() 是在 echo 一個不存在變數,此變數未定義,所以報錯:
class demo{
public $hello = 'Hello World';
function hello(){
echo $hello;
}
}
$demo = new demo;
$demo->hello();
在物件中,使用 $this 關鍵字來表示該物件本體 ,要注意,property 是屬於「物件本體全域」,所以物件中任何一個 method 都可以呼叫它:
class demo{
public $hello = 'Hello World';
function hello(){
echo $this->hello;
}
}
$demo = new demo;
$demo->hello(); //'Hello World'
Members 的可視性 (visibility)
public:不論在物件本體或外部程式,都可直接使用。
下例中,$name 為 public memeber,可在外部被改成 john:
class demo{
public $name = 'sam';
}
$demo = new demo;
echo $demo->name;
$demo->name = 'john';
echo $demo->name;
private:僅在該物件本體可使用,外部程式或繼承於本物件之子 class 無法使用。
改成 private 後,下面三行程式碼全部異常,會告知該 property 是 private member 無法使用:
class demo{
private $name = 'sam';
}
$demo = new demo;
echo $demo->name;
$demo->name = 'john';
echo $demo->name;
protected:僅物件本體及繼承的子類別可使用,外部程式無法叫用:
class animal{
protected $animal = 'cat';
protected function sleep(){
echo ' sleep';
}
}
class dog extends animal{
function sleep(){
parent::sleep();
}
function getAnimal(){
return $this->animal;
}
}
$dog = new dog;
echo $dog->getAnimal();
$dog->sleep();
Construction
核心概念
當物件生成時,強制預先去實作執行物件本身的功能。
使用原則
建構式僅用來做為設置預設 property 的存在:
class demo{
function __construct($name){
$this->name = $name;
}
}
$demo = new demo('sam');
範例 :
class Person{
private $name;
private $email;
public function __construct($name, $email){
//設置預設 property
$this->name = $name;
$this->email = $email;
echo __CLASS__.' created<br>';
// __CLASS__ class 的名字
}
public function getName(){
return $this->name.'<br>';
}
public function getEmail(){
return $this->email.'<br>';
}
$person1 = new Person('Nicolas', 'example@gmail.com');
echo $person1->getName();
// Person created
// Nicolas
構式僅用來做為預載 method 執行的存在:
class demo
function __construct(){
$this->Action();
}
function Action(){
}
}
範例 :
class Person{
private $name;
private $email;
public function __construct() {
$this->Action();
}
function Action() {
echo 'hello world!';
}
}
$person1 = new Person; // 建立物件時,會執行 Action() 印出 hellow world!
Inheritance
核心概念
所謂的繼承,就是將父類別所具備的特質特性完完全全的承襲過來。
基本使用
利用 extends
來繼承,childCLASS 中並沒有寫任何的 code,但因為它繼承了 parentCLASS,所以也具備了 parentCLASS 的所有特性:
class parentCLASS{
public $property1 = 'property1';
public $property2 = 'property2';
function method1(){...}
function method2(){...}
}
class childCLASS extends parentCLASS{
}
$child = new childCLASS();
$child->method1();
$child->method2();
父類別有本身具備的功能,子類別繼承後,除了具備父類別的功能。也可以自己編寫屬於自己的功能:
class parentCLASS{
public $property1 = 'property1';
public $property2 = 'property2';
function method1(){...}
function method2(){...}
}
class childCLASS extends parentCLASS{
public $property3 = 'property3';
function method2(){...}
}
$child = new childCLASS();
$child->method1();
$child->method2();
覆載
就算繼承父類別,還是可以去改變同名函式的內部功能:
class anumal{
function run(){
echo 'run';
}
function jump(){
echo 'jump';
}
function shout(){
echo '吼~~~~~~~~~~~~~~~~~~~~~~';
}
}
class dog extends animal{
function shout(){
echo '你吼你的我汪我的';
}
}
class cat extends animal{
function shout(){
echo '你吼你的我喵我的';
}
}
$dog = new dog();
$cat = new cat();
$dog->shout(); // 你吼你的我汪我的
$cat->shout(); // 你吼你的我喵我的
多形
你需要父類別的同名函式功能,又希望能寫自己的功能時,可以用parent:: 父類別方法()
的方式來使用父類別所提供的功能,然後在同名方法中寫入自己所要做的動作:
class animal{
function eat(){
echo '我要吃';
}
}
class dog extends animal{
private $eat;
function eat(){
$eat = parent::eat();
echo $eat.'肉';
}
}
$dog1 = new dog;
$dog1->eat(); // 我要吃肉
Private & Protected Member 的繼承問題
Private member 無法被繼承,以下程式會報錯:
class animal{
private $animal = 'cat';
private function sleep(){
echo ' sleep';
}
}
class dog extends animal{
}
$dog = new dog;
echo $dog->animal;
$dog->sleep();
如果希望父層的 member 不被外部使用,但可以被子類別使用,可以用 protected 來宣告:
class animal{
protected $animal = 'cat';
protected function sleep(){
echo ' sleep';
}
}
class dog extends animal{
function sleep(){
parent::sleep();
}
//因為在子類別重寫覆載,所以同名函式會視為 public
//如果父類別是用 private 則程式將會出錯
function getAnimal(){
return $this->animal;
}
}
$dog = new dog;
echo $dog->getAnimal();
$dog->sleep();
雖然外部程式無法呼叫父類別的 protected member,但上述 sleep() 在子類別被覆載時又變成了子類別的 public member,所以外部程式可以呼叫子類別的 sleep()。
Interface
核心概念
所謂的介面,我們可以當成是對物件的方法定義一個規範。任何要在我們的物件所有的功能,都必須遵從介面所定義的法方去實作該方法:
interface action{
public function run();
}
//上面就是要求物件實現的方法
class animal implements action{
function run()
}
}
// 應用了 action 這個介面,物件會要求實現上面 action 這個介面才可以通過編譯
虛擬類別
以下 animal 因為用了 action 的 interface,就算沒有需要 fast 方法,還是要在類別裡面放一個空的 fast 方法:
interface action{
public function run();
public function fast();
}
class animal implements action{
function run(){
$this->fast();
}
function fast(){
}
}
class dog extends animal{
function fast(){
echo 'very fast';
}
$dog = new dog;
$dog->run();
以下程式碼會報錯,因為在 dog 被實作的時候,父類別 animal 也會被實作:
class animal implements action{
function run(){
$this->fast();
}
}
class dog extends animal{
function fast(){
echo 'very fast';
}
}
如果想要 fast 方法只在子類別被實作,不由父類別產生,這是就可以就可以實作一個虛擬類別,當子類別被 new 的時候,animal 不會被實作:
abstract class animal implements action{
function run(){
$this->fast();
}
}
class dog extends animal{
function fast(){
echo 'very fast';
}
}