# 6. 物件導向 PHP
{%hackmd QnyEFBdERZebn4iQDXNPnA %}
[不錯的Cheat Sheet](https://www.codecademy.com/learn/learn-php/modules/classes-and-objects-in-php/cheatsheet)
- 概覽

## 01 了解PHP物件導向
## 02 OOP(Object Oriented Programming)概念
### 類別與物件
### 封裝
- 黑箱
### 繼承
- 子類別會從超類別(父類別)繼承屬性與動作
### 多型
- **不同的類別**對於**相同動作**可以有**不同的行為**
- e.g. 同是移動,但腳踏車與汽車的運動方式不同
## 03 使用PHP建立類別、屬性與動作
### 類別的結構
- 初始化
```php=
//1.最簡單類別定義式
class classname
{
}
//2.建立屬性
class classname
{
public $attribute1;
public $attribute2;
}
//3.建立方法
class classname
{
function operation1(){
}
function operation2($param1, $param2){
}
}
```
### 建構式
- PHP會在建立物件時呼叫建構式,以執行初始化工作(會自動呼叫)
```php=
class classname{
function __construct($param){
echo "Constructor called with parameter ".$param. "<br />";
}
}
```
### 解構式
- __destruct()
- 解構式不能接收參數
## 04 實例化類別
- new是關鍵字
```php=
$a = new Classname("First");
$b = new Classname("Second");
```
## 05 使用類別屬性
- 特殊指標$this,想要**設定**或**存取**類別裡的變數時:\$this->attribute (表示:**這是**我的屬性或方法!)
```php=
//類別中如何設定與存取一個屬性
class classname{
public $attribute;
function operation($param){
$this->attribute = $param;
echo $this->attribute;
}
}
```
## 06 呼叫類別動作(方法)
- 括號裡,傳入參數
```php=
$a = new classname();
$a->operation1();
$a->operation2(12, "test");
//若方法會回傳,可以使用其他變數捕捉回傳值
$x = $a->operation1();
$y = $a->operation2(12,"test");
```
## 07 使用private與public控制存取
- 定義:用來控制**屬性**與**方法**的可見度
- public
- 預設選項
- 可以在類別外部與內部存取公用項目
- private
- 只能在類別裡直接被存取
- private的項目不會被繼承
- protected
- 介於public與private之間
- 只能在類別裡被存取
```php=
class manners{
private $greeting = 'Hello';
public function greet($name){
echo "$this->greeting, $name";
}
}
//可以省略public,因為他是預設值。不過,若你要使用其他修飾符號的話,使用public可讓程式可讀性提高
```
## 08 編寫存取函式
- OOP優點 => 鼓勵封裝
- 使用__get, __set強制做到封裝
```php=
class classname{
private $attribute
function __get($name){
return $this->$name;
}
function __set($name, $value){
$this->$name = $value;
}
}
//__get()只會回傳$attribute的值
//__set()會指派一個新值給$
--------------------------------------
//它們是如何工作?若輸入以下:
$a = new classname();
//使用public時,不會用到__get(), __set()屬性
$a->attribute = 5;
//私下呼叫__set(),使用$name設為attribute,$value設為5
$a->attribute
//私下呼叫__get(),並將參數$name設為attribute
//優點:藉由單一的存取處,可以自由地修改底層的實作
```
## 09 使用PHP實作繼承
- 使用extends
```php=
//A是父類別,B是子類別(記法:extends自父類別)
class B extends A{
public $attribute2;
function operation2(){
}
}
//如果A類別被宣告成:
class A {
public $attribute1;
function operation1(){
}
}
//以下B的物件方法與屬性都是有效的
$b = new B();
$b->operation1();
$b->attribute1=10;
$b->operation2();
$b->attribute2 = 10;
//注意!繼承只有單方向!子類別可以繼承父類別,但父類別無法繼承子類別
```
### 使用private 與 protected控制繼承的可見度
- 使用private
- 不被繼承
- 使用protected
- 無法在類別外被看到(類別裡才可以被看到會呼叫)
- 會被繼承
```php=
<?php
class A{
private function operation1(){
echo "operation1 called";
}
protected function operation2(){
echo "operation2 called";
}
public function operation3(){
echo "operation3 called";
}
}
class B extends A{
function __construct(){
$this->operation1();
$this->operation2();
$this->operation3();
}
}
$b = new B();
?>
//$this->operation1(); 會產生嚴重錯誤(因為private無法被繼承)
//檔案最後一行加入$this->operation2(),也會嚴重錯誤(因為protected在類別外被呼叫)
//$this->operation3() 可以執行(因為public類別內外都可以存取)
```
### 覆寫(Override)
- 子類別**修改**與父類別屬性、方法,稱為覆寫
```php=
class A {
public $attribute = 'default value';
function operation(){
echo 'Something<br />';
echo 'The value of $attribute is '.$this->attribute.'<br />';
}
}
//子類別想要改變$attrubte的值,或讓operation()有新功能。使用B覆寫$attribute與operation()
class B{
public $attribute = 'different value';
function operation(){
echo 'Something else<br />';
echo 'The value of $attribute is '.$this->attribute.'<br />';
}
}
//宣吿B不會影響A
---------------------------------------
//B若要呼叫父類別的原始版本怎麼辦?
parent::operation()
//即A::operation(),但會使用B裡面的attribute,而不是A的attribute
```
### 使用final避免(函式)被繼承與覆寫
- 函式前加入final,無法被子類別繼承
```php=
class A {
public $attribute = 'default value';
final function operation(){
echo 'Something<br />';
echo 'The value of $attribute is'.$this->attribute.'<br />';
}
}
//可防止B覆寫operation()
------------------------------------------------------------
//如何完全防止一個類別被繼承?(完全不能被繼承)
final class A{
}
```
### 多重繼承
- PHP不支援多重繼承
- 即,每一個子類別**只能繼承一個**父類別
- PHP提供以下兩類機制來利用多重繼承的優點
- 1. 介面(interface)
- 多重繼承的替代方案
```java=
interface Displayable(){
function display();
}
class webPage implements Displayable{
function display()
}
//webPage類別可以繼承一個類別,並實作一或多個介面
```
- 2. 特徵(traits)
- 與介面的差異:特徵可包含實作,而非只是指定一個必須實作的介面
- 可以結合許多特徵
```php=
//藉由建立類別的方式來建立特徵
trait logger{
public function logmessage($message, $level='DEBUG'){
//$將$message寫至紀錄
}
}
//如何使用特徵?
class fileStorge{
use logger; //use是使用trait的關鍵字
function store($data){
//...
$this->logmessage($msg);
}
}
```
## 10 進階PHP OOP功能
- Static (靜止)
- Scope Resolution Operator (::)