[ 筆記 ] OOP - 物件導向基礎概念


Posted by krebikshaw on 2020-08-01

PHP 與 MySQL 的連線

(這段程式碼太好用了所以先置頂)

  • 可以以兩個 php 檔來處理連線工作
    1. DB_config.php : 放 server & user & db 資料
    2. DB_conn.php : 連線、取資料等初始化動作

DB_config.php

<?php
  $servername = 'localhost';
  $user = 'root';
  $password = '';
  $dbname = 'jobs';
?>

DB_conn.php

<?php
  require_once('./DB_config.php');

  class Db {
    public function __construct($servername, $user, $password, $dbname) {
      $this->server = $servername;
      $this->user = $user;
      $this->pass = $password;
      $this->db = $dbname;
      $this->init();
    }
    private function init() {
      $this->conn = mysqli_connect($this->server, $this->user, $this->pass, $this->db);
      if ($this->conn->connect_error) {
        die('Failed: ' . $this->conn->connect_error);
      }
      mysqli_query($this->conn, "SET NAMES utf8");
      mysqli_query($this->conn, 'SET time_zone = "+8:00"');
    }

    public function query($str) {
      $this->result = mysqli_query($this->conn, $str);
    }

  // 拿到所有資料
    public function fetch_array() {
      while ($row = mysqli_fetch_array($this->result, MYSQLI_ASSOC)) {
        printf("ID: %s  title: %s", $row["id"], $row["title"] . " <br>");
      }
    }  
  }

  $db = new Db($servername, $user, $password, $dbname);
?>

使用資料時,new 出一個 DB Class

<?php
  require_once('./DB_config.php');
  require_once('./DB_conn.php');

  $sql = "SELECT * FROM jobs";
  $db->query($sql);
  echo $db->fetch_array(); // 印出所有 id & title
?>

(以下 正片 開始)

物件導向概念

  • 物件導向應用在軟體設計的發展,著重在物件的 分解相互作用
  • 一個完整的物件會包含:
    • 屬性(Attribult):物件的靜態外觀描述,例如 class 中的 member data
    • 方法(method):物件的動態回應方式,例如 class 中的 member method
    • 事件(event):物件針對外部事件做出的反應

命名規範

  • 類別和介面:第一個字母為大寫,ex. Student, StudentName
  • 成員變數和成員方法:駝峰式命名,ex. setColor
  • 套件:全部小寫,ex. java.io java.lang.math
  • 常數:全部大寫並用 _ 連接,ex. PI MAX_VALUE

類別 class

  • 類別是用來具體描述物件狀態與行為的資料型態
  • 「類別」與「物件」之間的關係就像「設計圖」與「建築物」
    • 「類別」只是個架構
    • 「物件」是實際存在的實體
  • 把「類別」實際製作後的成品就是「物件」,這個動作就叫做「實作」

實作:將設計圖變成建築物

  • 物件實作宣告方式:<物件名稱> = new <類別名稱>
  • class 命名時開頭字母要大寫

  • 底下範例可以看到,

    • name 是物件的「實體變數」
    • setName, getName 是物件的 「方法」
  • this 指的是當下的這個 「實體物件」instance

    • 如果是 let dog1 = new Dog() ,this 指的就是 dog1
    • 如果是 let dog2 = new Dog() ,this 指的就是 dog2

function 在物件外面是 function,在物件裡面是 method

JavaScript

class Dog {
  setName(name) {
    this.name = name;
  };
  getName() {
    return this.name;
  }
}

let dog1 = new Dog();
dog1.setName("Halu");
console.log(dog1.getName());  // Halu

PHP

<?php
  class Dog {
    public function setName($name) {
      $this->name = $name;
    }
    public funtion getName() {
      return $this->name;
    }
  }

  $dog1 = new Dog()
  $dog1.setName("Halu");
  echo $dog1.getName();
?>

存取層級 & 修飾字

  • 存取層級,設定誰可以使用此內容
    • public:代表所有的類別都可以使用
    • private:代表只有此類別本身才能使用
    • protected:代表只有該類別的衍生類別或在相同套件裡的類別才能用

封裝 Encapsulation

  • 意思是說把細節藏起來,所以對外圍可以使用的接口,會變得非常單純。所以是說把常用的方法打開,但方法底層是怎麼實作的,使用者不需要關心。
<?
Class Dog {
    public function hello() { 
      echo $this->getHelloSentence(); // => 對外接口
    }
    private function getHelloSentence() { // => 藏起來的細節
      return 'hello, I am a dog.';
    }
}
$dog = new Dog();
$dog->hello();
?>

getter & setter

  • 用於設定及取得「實體變數」
  • 可於存取的時候設置條件,來確保資料資料在不如預期的時候就把它擋住、不能存取。
<?php
Class Dog {
  private $name = 'default';
  public function hello() { 
    echo $this->getHelloSentence();
  }
  private function getHelloSentence() {
    return 'hello, I am '. $this->name . '<br>';
  }

  // setter 
  public function setName($name) {
    if ($name === 'Fuck') return // => 如果是髒話就不能設置
    $this->name = $name;
  }
  // getter
  public function getName() {
    return $this->name;
  }
}
?>

Constructor 建構子

  • 除了利用 setter 設定「實體變數」,我們可以利用 Constructor,在一開始 new 一個新的物件的時候直接設定變數
  • 也可以利用 Constructor,建立 init() 初始化設定。

JavaScript

class Dog {
  constructor(id, name, age) {
    this.id = id;
    this.name = name;
    this.age = age;
  }
}

let dog1 = new Dog(1, "Halu", 3)
// 如此一來不用一個一個設定, dog1.setName("Halu"); dog1.setId(1); dog1.setAge(3);

PHP

<?php 
  class Dog {
    public function __construct($id, $name, $age) {
        $this->id = $id;
        $this->name = $name;
        $this->age = $age;
        $this->init();
    }

    private function init() {
        echo $this->say();
    }

    private function say() {
        return $this->id . $this->name . "<br>";
    }

    public function speak($str) {
        echo $str;
    }
  }

  $go = new Test(1, "Halu", 3); // 1Halu
  $go->speak("what") // what
?>

mysqli_fetch_array 存取欄位陣列

  • MYSQLI_ASSOC 用欄位名稱選擇( $row['id'], $row['title'] )
  • MYSQL_NUM 用陣列位置選擇 ( $row[0], $row[1] )
  • 如果沒有輸入選擇方式的話,預設是選擇 MYSQL_BOTH
    • 兩者皆可用( $row[0], $row['id'] )

繼承 Inheritance

  • extends 繼承自另一個 Class
  • 某一個 class 如果跟新的 class 很像,可以用 extends 去取得父物件的屬性。

  • super 改變父 Class 的方法

  • 可以基於父 Class 的方法做一些改變與微調。

  • 其他程式語言應該都是用 super 這個關鍵字,但在 PHP 是用 parent::<method> 語法

JavaScript

Class Calculator {
    constructor() {
        this.text = '';
    }
    input(str) {
        this.text = str;
    }
    getResult() {
        return eval(this.text);
    }
}
Class chineseCalculator extends Calculator {
    input(str) {
        if (str === '三') {
            super.input(3); // => super 語法
        } else {
            super.input(str);
        }
    }
}

PHP

<?php
Class Animal {
  private $name = 'default';

  // 初始化
  public function __construct($name) {
    $this->name = $name;
  }
  public function hello() { 
    echo $this->getHelloSentence();
  }
  private function getHelloSentence() {
    return 'hello, I am '. $this->name . '<br>';
  }
}
Class Dog extends Animal { // => 繼承
  public function run() {
    echo $this->name . 'is running';
  }
  public function sayYoAndHello() {
    echo 'Yo';
    parent::hello(); // => 執行 Animal 的 hello 函式
  }
  // public function hello() { // => overwrite
  // ...
  // }
}
$dog1 = new Dog('Leo');
$dog1->hello(); // => hello, I am Leo

$dog2 = new Dog('Amy');
$dog2->hello(); // => hello, I am Amy
?>

Static 靜態方法

  • 上面說過在 class 中的 function 叫做 method
  • 有些 class 中的 function 是要給「實體物件」用的
    • 像是:public function setName($name) 是要給外面存取的
    • 利用「實體物件」來呼叫:$dog1->setName("Halu")
  • 有些 class 中的 function 是只有 class 自己要用的
    • 像是:private static function caculate()
    • 要利用 class 自己來呼叫:Dog::caculate()
  • static 這個方法不一定只能使用在 function
    • 也可以利用相同的概念,設定一個只給 class 使用的變數
    • 像是:static $number = 1
    • 也是讓 class 自己來呼叫:Dog::$number
  • 由於 static 的方法或變數,是給 class 自己用的,所以不論這個 class 被 new 多少次,這個 static 的方法或變數都只會有一個
    • 我們會說 Dog::$number,其中的 $number 只有一個
  • 但是非 static 的方法會變數,每一次被 new 成新的「物件」,就會產生對應的新方法及變數
    • $dog1->setName("Halu")$dog2->setName("Alu") 是兩個不同 instance 底下的方法,所以我們可以說有兩個 setName()

實作技巧

  • 要實作一個 class 你可以先思考,你要如何讓別人來使用這個 class
    • 舉例:要實作一個 XMLHttpRequest 的 class
class XMLHttpRequest {
  // 我先什麼都不寫
}

// 開始思考希望別人能怎麼用這個 class
const request = new XMLHttpRequest();
request.open(method, url, true) // 讓別人可以傳 method, url, 設定同步異步
request.onload = () => { } // 讓別人可以設訂 callback function
request.onerror = () => { } // 讓別人可以除錯
request.send() // 讓別人可以發送 request

//如此一來,這些 method 就要設定成 public,成為可以對外使用的接口
//我再來設計 class 的內容

#OOP







Related Posts

MTR04_0702

MTR04_0702

MTR04_0626

MTR04_0626

#3 工程數學

#3 工程數學


Comments