[PHP] 物件導向 PHP 入門


Posted by Nicolakacha on 2020-09-11

本篇會介紹基礎的物件導向 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';
    }
}

#PHP







Related Posts

Cmder 更改 lambda λ 符號

Cmder 更改 lambda λ 符號

Python Type Annotations for a Generator

Python Type Annotations for a Generator

【隨堂筆記】套件模組與環境設定

【隨堂筆記】套件模組與環境設定


Comments