顯示具有 PHP::類別與介面 標籤的文章。 顯示所有文章
顯示具有 PHP::類別與介面 標籤的文章。 顯示所有文章

2021年3月14日 星期日

PHP 的 Trait 用法

設定目標:
  • 了解 PHP 如何使用 Trait 來解決跨類別問題

Trait 概念與實作
  1. 特徵(Trait)
    • Trait 與抽象類別相似,無法使用 new 來產生物件(被實例化)!
    • 因為 PHP 只能單一繼承,所以無法跨多個類別使用這些類別內的方法!
    • 為了減少程式碼的重複撰寫,所以 PHP 使用 Trait 來克服這個問題!
    • 使用 Trait 可以讓 PHP 實現單一類別(Singleton)的使用!
    • 單一 Trait 使用範例 :
      • oneTrait.php
        <?php
        class Base {
          public function sayHello() {
            echo 'Hello ';
          }
        }
        trait SayWorld {
          public function sayHello() {
            parent::sayHello();
            echo 'World!';
          }
        }
        class MyHelloWorld extends Base {
          use SayWorld;
        }
        
        $o = new MyHelloWorld();
        $o->sayHello();
        ?>
        
    • 多個 Trait 使用範例 :
      • multiTrait.php
        <?php
        trait Hello {
          public function sayHello() {
            echo 'Hello ';
          }
        }
        trait World {
          public function sayWorld() {
            echo 'World';
          }
        }
        class MyHelloWorld {
          use Hello, World;
          public function sayExclamationMark() {
            echo '!';
          }
        }
        $o = new MyHelloWorld();
        $o->sayHello();
        $o->sayWorld();
        $o->sayExclamationMark();
        ?>
        
      • integrateTrait.php
        <?php
        trait Hello {
          public function sayHello() {
            echo 'Hello ';
          }
        }
        trait World {
          public function sayWorld() {
            echo 'World';
          }
        }
        trait HelloWorld{
          use Hello, World;
        }
        class MyWorld{
          use HelloWorld;
        }
        $world = new MyWorld();
        echo $world->sayHello() . " " . $world->sayWorld(); //Hello World
        ?>
        
    • 優先序問題
      • Trait 內可以使用 overwrite 功能來覆蓋父類別有的功能!
      • 優先序的範例 : orderTrait.php
        <?php
        trait Hello{
          function sayHello() {
            return "Hello";
          }
          function sayWorld() {
            return "Trait World";
          }
          function sayHelloWorld() {
            echo $this->sayHello() . " " . $this->sayWorld();
          }
          function sayBaseWorld() {
            echo $this->sayHello() . " " . parent::sayWorld();
          }
        }
        
        class Base{
          function sayWorld(){
            return "Base World";
          }
        }
        class HelloWorld extends Base{
          use Hello;
          function sayWorld() {
            return "World";
          }
        }
        $h =  new HelloWorld();
        $h->sayHelloWorld(); // Hello World
        ?>
        
    • Trait 的衝突與別名 : 使用 insteadof 與 as
      • 利用 insteadof 來解決不同 Trait 但相同方法名稱的問題
      • 例 : 有一衝突的範例 confuse.php
        <?php
        trait Game{
          function play() {
            echo "Playing a game";
          }
        }
        trait Music{
          function play() {
            echo "Playing music";
          }
        }
        
        class Player{
          use Game, Music;
        }
        $player = new Player();
        $player->play();
        ?>
        
        PS: 以上範例有兩個 Trait ,有相同的方法名稱 play()!在使用當下,就會發生衝突!
      • 修改後的 confuse.php 如下:
        <?php
        trait Game{
          function play() {
            echo "Playing a game";
          }
        }
        trait Music{
          function play() {
            echo "Playing music";
          }
        }
        
        class Player{
          use Game, Music{
            //將 Game 的 play 別名成 gamePlay
            Game::play as gamePlay;
            //使用 Music 的 play 功能,取消 Game 的 play 功能!
            Music::play insteadof Game;
          }
        }
        $player = new Player();
        $player->play();
        $player->gamePlay();
        ?>
        
  2. Trait 其它功能
    • 利用 Trait 獨特的使用功能,可以取得 private 權限的類別屬性值
      • 例 : getPritrait.php
        <?php
        trait Message {
          function alert() {
            echo $this->message;
          }
        }
        class Messenger {
          use Message;
          private $message = "This is a message";
        }
        
        $messenger = new Messenger;
        $messenger->alert(); //This is a message
        ?>
        
    • 利用 Trait 內可抽象化方法,強迫使用該 Trait 的類別,實作該抽象方法!
      • 例 : abtractTrait.php
        <?php
        trait Message {
          private $message;
              
          function alert() {
            $this->define();
            echo $this->message;
          }
          abstract function define();
        }
        
        class Messenger {
          use Message;
          function define() {
            $this->message = "Custom Message";
          }
        }
        
        $messenger = new Messenger;
        $messenger->alert(); //Custom Message
        ?>
        
    • Trait 的 use 與類別導入的 use 是不同的功能
      • Trait 的 use : 置放於 class 內部!
      • 類別導入的 use : 置放於 class 外部!

本章練習:
  • 修改你的 Human 類別,讓它可以使用 Bird 類別中的 fly 方法!

PHP 的命名空間

設定目標:
  • 了解 PHP 如何定義命名空間,改善自動載入的缺點!

命名空間概念與實作
  1. 命名空間(Namespace)
    • PSR 規範 : PHP-FIG 提出的規範,目的是讓 PHP 開發者在撰寫時有一個建議規範可遵循,使得開發者間可進行有效溝通與開發!
    • PSR-4 規範了一套 namespace 統一作法,包含了原有的 PSR-0 所規範的 autoload 作法!
    • 利用Composer 來進行 autoload 可提昇編輯效率!
    • PHP 檔案內的關鍵字 :
      • namespace : 定義類別的完整類別名稱
      • use : 導入需要使用的類別名稱
    • PSR-4 正確的命名空間,其完整的類別名稱語法如下 :
      \<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
      
      • 完整的類別名稱(fully qualified class name)必須有最高層級(top-level)的命名空間(namespace),通常稱這個命名空間為「供應商命名空間(vendor namespace)」。
      • 完整的類別名稱可以有一個或多個子命名空間。
      • 一個完整的類別名稱必須以類別名稱結束。
      • 在完整的類別名稱中,底線沒有其他意義。
      • 完整的類別名稱可以由英文字母大小寫組合而成。
      • 所有的類別名稱必須是有區分大小寫的。
    • 重點 :
      • 命名空間 + 類別名稱 = 路徑 + 檔名.php
      • 命名空間、類別,都需要開頭大寫
      • 底線不要拿來當作分類,例如 : Like_Book.php、Like_Movie.php,應該改成路徑 Like/Book.php、Like/Movie.php
  2. 實作範例:
    • 安裝 Composer 至專案目錄內!(Windows 使用者可以參考這一篇)
      # yum install wget
      # cd /usr/share/nginx/html
      # wget https://getcomposer.org/installer -O composer-installer.php
      # php composer-installer.php --filename=composer --install-dir=/usr/local/bin
      # composer --version
      
    • 建立測試用目錄 :
      +Hello
      ++public
      ++-index.php
      ++src
      +++Cars
      +++-Car.php
      ++vendor (該目錄由 composer 自建,一開始不用手動建立)
      +++composer
      ++-autoload.php
      +-composer.json
      
    • 編寫 composer.json
      {
        "autoload": {
          "psr-4": {
            "Cars\\": "src/Cars"
          }
        }
      }
      
    • 初次建立名稱空間
      # composer dump-autoload
      
    • 開始建立 PHP 類別程式
      • 建立 Cars/Car.php
        <?php
        namespace Cars;
        
        class Car{
        
          protected $name;
        
          public function setName($name){
            $this->name = $name;
            return "completed...";
          }
        
          public function getName(){
            return $this->name;
          }
        }
        ?>
        
      • 建立 public/index.php
        <?php
        require_once '../vendor/autoload.php';
        
        use \Cars\Car;
        $mycar = new Car();
        $mycar->setName("Ford...");
        echo $mycar->getName();
        ?>
        
      • 使用瀏覽器 http://你的IP/Hello/public/index.php
    • 增加新的類別 : Customers
      • 在 src 目錄下建立新的目錄 Customers
        # mkdir /usr/share/nginx/html/Hello/src/Customers
        
      • 修改 composer.json
        • 加入 Customers 路徑的對應
          {
            "autoload": {
              "psr-4": {
                "Cars\\": "src/Cars",
                "Customers\\": "src/Customers"
              }
            }
          }
          
        • 再執行一次 composer
          # composer dump-autoload
          
        • 開始新增新的類別 Customer
          • 在 src/Customers 目錄下,新增 Customer.php
            <?php
            namespace Customers;
            
            class Customer{
              protected $cname;
              public function setName($cname){
                $this->cname = $cname;
                return "completed...";
              }
              
              public function getName(){
                return $this->cname;
              }
            }
            ?>
            
          • 修改 index.php 檔案內容
            <?php
            require_once '../vendor/autoload.php';
                
            use Cars\Car;
            use Customers\Customer;
                    
            $mycar = new Car();
            $mycar->setName("Ford...");
            echo "My Car: ".$mycar->getName();
            echo "
            "; $myprofile = new Customer(); $myprofile->setName("Peter"); echo "My Name: ".$myprofile->getName(); ?>
          • 在 Customers 下增加子目錄 Block
            # cd /usr/share/nginx/html/Hello/src
            # mkdir Customers/Block
            
          • 在 Block 目錄下,增加一個 Blocklist.php
            <?php
            namespace Customers\Block;
            
            use Customers\Customer;
            
            class Blocklist extends Customer {
            
              protected $state;
                    
              public function setState($state){
                $this->state = $state;
                return "Complete...";
              }
                    
              public function getState(){
                return $this->state;
              }
            }
            ?>
            
          • 修改 index.php 檔案內容
            <?php
            require_once '../vendor/autoload.php';
                
            use Cars\Car;
            use Customers\Customer;
            use Customers\Block\Blocklist;        
                    
            $mycar = new Car();
            $mycar->setName("Ford...");
            echo "My Car: ".$mycar->getName();
            echo "
            "; $myprofile = new Customer(); $myprofile->setName("Peter"); echo "My Name: ".$myprofile->getName(); echo "
            "; $mystate = new Blocklist(); $mystate->setState("Forzien..."); echo $mystate->getState(); ?>
          • 使用瀏覽器 http://你的IP/Hello/public/index.php

本章練習:
  • 修改你的 dog 、cat 以及 human 的所有類別,讓他們有自己所屬目錄,並且可以自動導入到執行程式中!

2021年3月13日 星期六

PHP 的自動載入功能

設定目標:
  • 了解 PHP 如何自動載入需要的模組程式

模組自動載入
  1. PHP 原有的模組載入方式
    • include : 載入其他的 php 程式檔!當執行錯誤時,不會停止程式運作!
    • include_once : 相同的檔案,只會載入一次!
    • require : 載入其他的 php 程式檔!當執行錯誤時,會停止程式運作!
    • reuqire_once : 相同的檔案,只會載入一次!
  2. 缺點 : 若需要載入大量檔案程式,程式碼將會十分難看與難以除錯與管理!
  3. PHP 自動導入模組方式
    • 當須要用到該使用的物件時,才去真正的引入該類別
    • __autoload 用法 :
      • 例 : 有一個目錄 Classes ,裡面有個 Member.php 的檔案,Classes 目錄外面有兩個檔案 autoload.php 以及 index.php
        +Classes
        +--Member.php
        -autoload.php
        -index.php
        
      • Member.php 檔案內容:
        <?php
        //這是 Classes/Member.php
        class Member{
          public function getMemberList(){
            echo "print member list...
        "; } } ?>
      • autoload.php 檔案內容:
        <?php
        function __autoload($className){
          $filename = __DIR__ . "/classes/" . $className . ".php";
          if (is_readable($filename)){
            require $filename;
          }
        }
        ?>
        
      • index.php 檔案內容:
        <?php
        //這是 index.php
        include_once __DIR__ . "/autoload.php";
        
        $member = new Member();
        $member->getMemberList();
        ?>
        ?>
        
      • 缺點 : __autoload() 不能重覆的被定義!
  4. 使用 SPL(Standard PHP Library)
    • spl_autoload:
      • 預設實作 __autoload() magic function
      • 當 spl_autoload_register() 沒有定義或是沒有帶任何參數的時候,預設會採用 __autoload() 這個 function
    • spl_autoload_register
      • 能夠註冊自行定義的 autoload function
      • 當 spl_autoload_register() 有註冊之後,__autoload() 將會失效,必需自己手動將 __autoload() 註冊,才能使用。
    • 例 : 在原來的範例目錄內,增加 first 以及 second 這兩個目錄以及 First.php 與 Second.php 兩個檔案!另外再新增兩個 firstAutoload.php 以及 secondAutoload.php 檔案!
      +Classes
      +--Member.php
      +first
      +--First.php
      +second
      +--Second.php
      -firstAutoload.php
      -secondAutoload.php
      -autoload.php
      -index.php
      
    • First.php 檔案內容:
      <?php
      //這是 first/First.php
      class First{
        public function doSomething(){
          echo "I am first class...
      "; } } ?>
    •     
    • Second.php 檔案內容:
      <?php
      //這是 second/Second.php
      class Second{
        public function doSomething(){
          echo "I am second class...
      "; } } ?>
    •     
    • firstAutoload.php 檔案內容:
      <?php
      //這是 firstAutoload.php
      function firstAutoload($className){
        $filename = __DIR__ . "/first/" . $className . ".php";
        if (is_readable($filename)){
          require $filename;
        }
      }
      //向 spl_autoload 註冊這個方法的名稱
      spl_autoload_register('firstAutoload');
      ?>
      
    •     
    • secondAutoload.php 檔案內容:
      <?php
      //這是 secondAutoload.php
      function secondAutoload($className){
        $filename = __DIR__ . "/second/" . $className . ".php";
        if (is_readable($filename)){
          require $filename;
        }
      }
      //向 spl_autoload 註冊這個方法的名稱
      spl_autoload_register('secondAutoload');
      ?>
      
    • 修改 index.php 檔案內容:
      <?php
      //修改後的 index.php
      include_once __DIR__ . "/firstAutoload.php";
      include_once __DIR__ . "/secondAutoload.php";
      
      $first = new First();
      $first->doSomething();
      
      $second = new Second();
      $second->doSomething();
      ?>
      
    • 缺點 : 每新增一個目錄,就需要寫一個 autoload 檔案!不好管理!
    • 改進方式 : 寫一個 allAutoload.php,再使用 array、foreach 導入!
      <?php
      //這是 allAutoload.php
      function allAutoload($className){
      $folders = array(__DIR__ . "/first/",
                       __DIR__ ."/second/",
                       );
      
      foreach ($folders as $folder){
          $fileName = $folder . $className . ".php";
          if (is_readable($fileName)){
             require $fileName;
          }
        }
      }
      
      //註冊
      spl_autoload_register('allAutoload');
      ?>
      
    • 再次修改 index.php 檔案內容:
      <?php
      //又修改了 index.php
      include_once __DIR__ . "/allAutoload.php";
      $first = new First();
      $first->doSomething();
      
      $second = new Second();
      $second->doSomething();
      ?>
      
    • 缺點 : 每次新增一個 class 目錄,就要異動一次 autoload 檔案!

本章練習:
  • 修改你的 dog 、cat 以及 human 的所有類別,讓他們可以自動導入到執程式中!

PHP 多型方法與多載功能

設定目標:
  • 了解 PHP 如何使用多型方法
  • 了解 PHP 如何使用多載功能

多型概念與使用方法
  1. 多型(Polymorphism)
    • 使用概念與方法:
      • 有繼承的關係才能使用多型
      • 利用有相同父類別的關係,進行不同子類別的方法實作,產生不同的結果!
    • 例:demo5.php
      <?php
      abstract class Animal {
        public function sleep(){
            echo '睡';
        }
      }
      class Dog extends Animal {
        public function move(){
            echo '跑';
        }
      }
      class Bird extends Animal{
        public function move()
        {
            echo '飛';
        }
      }
      class Action{
        public function actionMove(Animal $obj)
        {
            $obj->move();
        }
      }
      
      $dog = new Dog();
      $bird = new Bird();
      $action = new Action();
      $action->actionMove($dog);
      $action->actionMove($bird);
      ?>
      
多載功能的應用
  1. 多載(overloading)
    • PHP 無法像其他物件導向程式語言,可以利用相同名稱,不同參數屬性值來實作多載功能!
    • PHP 利用自定義的 Magic methods 來實作多載功能!
    • 屬性多載的 magic function :
      • __set(): 若有屬性名稱是設定未定義或無法讀取的,就「設定」對應的屬性值!
      • __get(): 若有屬性名稱是設定未定義或無法讀取的,就「取得」對應的屬性值!
      • __isset(): 查詢某個屬性是否有被定義!
      • __unset(): 解除某個屬性定義值!
      • 範例 : Person.php
        <?php
          class Person {
              private $sex;
              public function __set($name, $value){
                
                //限制不可動態產生屬性
                if (isset($this->$name)) {
                    return $this->$name = $value;
                } else {
                    return null;
                }
              }
              // 取得屬性名稱的值
              public function __get($name){
                return $name;
              }
              // 判斷是否有該屬性參數   
              public function __isset($name){
                return $name;
              }
              // 取消該屬性
              public function __unset($name){
                return $name;
              }
            }
            
            $person = new Person();
            //Person 類別沒有 name 這個屬性名稱
            //PHP_EOL 空隔或是換行
            $person->name = 'PHP';
            echo $person->name.PHP_EOL;
            // sex 這個屬性是無法取得的
            echo $person->sex.PHP_EOL;
            echo isset($person->address);
            unset($person->name);
        ?>
        
    • 方法多載的 magic functions :
      • __call() : 當呼叫一個未定義的物件方法時,會呼叫本法函數!
      • __callStatic() : 當呼叫一個未定義的靜態物件的方法時,會呼叫本法函數!
      • 例 : Shape.php
        <?php
        class Shape {
          const PI = 3.142 ;
          // name 是方法名稱,arg 則是陣列名稱
          function __call($name,$arg){
            if($name == 'area')
              switch(count($arg)){
                case 0 : return 0 ;
                //self 指物件自己
                case 1 : return self::PI * $arg[0] ;
                case 2 : return $arg[0] * $arg[1];
              }
          }
          function __callStatic($name,$arg){
            return array(3,5);
          }
        }
        $circle = new Shape();
        echo $circle->area(3);
        $rect = new Shape();
        echo $rect->area(8,6);
        echo Sharp::hello()[1];
        ?>
        

本章練習:
  • 寫個利用衣服的類別,讓你的 dog 、cat 以及 human 穿上適合的衣服!
  • 寫個檢查有沒有穿衣服的方法,讓 dog 、cat 不用穿衣服,以及 human 穿上泳衣!

PHP 靜態屬性與匿名類別

設定目標:
  • 了解 PHP 靜態屬性的用法
  • 了解 PHP 匿名類別概念與應用方法

靜態屬性概念與使用方法
  1. 靜態屬性(static)
    • 作用:
      • 用於不會改變的類別屬性與方法
      • 不需要實例化產生物件,直接呼叫類別即可使用
    • 例:MathRate.php (計算複利用的方法)
      <?php
      class MathRate{
        public static function ComplexRate($principal,$yearRate,$period,$years){
           $result = 0;
           $result =  $principal * pow((1 + ((float)$yearRate/$period)),($period*$years));
           return $result;
        } 
      }
      ?>
      
    • 利用一個 demo4.php 來實現上述程式:
      <?php
        include "MathRate.php";
        echo MathRate::ComplexRate(1000,0.18,12,3);
      ?>
      
匿名類別觀念與應用
  1. 匿名類別(Anonymous class)
    • 作用
      • 有些類別用完即丟,沒有需要一直存在,即可使用匿名類別,減輕程式的複雜程度!
    • 範例 : Application.php
      <?php
      interface Logger {
        public function log(string $msg);
      }
      class Application {
        private $logger;
        public function getLogger(): Logger {
          return $this->logger;
        }
        public function setLogger(Logger $logger) {
          $this->logger = $logger;
        }
      }
      $app = new Application;
      // 使用 new class 建立匿名類別
      $app->setLogger(new class implements Logger {
        public function log(string $msg) {
          print($msg);
        }
      });
      
      $app->getLogger()->log("這是一個匿名類別的例子");
      ?>
      

本章練習:
  • 寫個疫苗的匿名類別,讓你的 dog 以及 cat 接種疫苗!
  • 寫個計算寵物一年花費的費用計算靜態程式,算一下你的寵物一年的花費!

PHP 介面與抽象類別的應用

設定目標:
  • 了解介面與抽象類別的概念
  • 實作介面與抽象類別的方法

介面概念與使用方法
  1. 介面(interface)
    • 作用:
      • 定義相同的功能名稱,但可以由執行的類別,各自實作功能!
      • 有實作介面的類別,一定要實作內容!
      • 介面可以繼承其他的介面!
      • 類別可以同時執行多個介面!
    • 例:Bark.php (吠叫...)
      <?php
        interface Bark{
          public function bark();
        }
      ?>
      
    • 例:Swim.php (游泳...)
      <?php
        interface Swim{
          public function swim();
        }
      ?>
      
    • 例:Human.php (建一個人類的類別...)
      <?php
        include "Bark.php";
        include "Swim.php";
        class Human implements Bark, Swim{
          public function bark(){
            echo "人類叫聲...是在叫什麼啦!!";
          }
          public function swim(){
            echo "人類在游泳...不是在洗澡嗎?";
          }
        }
      ?>
      
    • 利用一個 demo3.php 來實現上述幾個程式:
      <?php
        include "Human.php";
        $man = new Human();
        echo $man->bark();
        echo $man->swim();
      ?>
      
抽象類別觀念與應用
  1. 抽象類別 (Abstract)
    • 作用
      • 父類別在使用介面之後,必須要實作該介面功能內容!
      • 子類別在繼承父類別之後,如想要改變介面功能內容,必須使用覆寫的方式!
      • 父類別若不想實作介面方法,子類別又需要定義介面功能,可以將父類別抽象化,即可不用實作介面方法!
      • 子類別繼承抽象父類別之後,必須要實作父類別的介面方法!
    • 範例 : 修改 dog.php
      <?php
      include "Bark.php";
      abstract class dog implements Bark {
         // 設定狗的屬性
         public $name;
         public $color;
         public $style;
         
         //設定建構子
         public function __construct($name,$color,$style){
           $this->name = $name;
           $this->color = $color;
           $this->style = $style;
         }
      
         public function dogRun(){
           echo "狗狗跑步中...";
         }
         // 修改狗叫的功能
         public function Bark(){
           //這裡保持空白
         }
      
         public function __destruct(){
           echo "狗狗回家了...";
         }
      }
      ?>
      
    • 範例 : 修改 Poodle.php
      <?php
      include "dog.php";
      
      class Poodle extends dog{
        protected $size;
      
        public function __construct($name,$color,$style,$size){
          parent::__construct($name,$color,$style);
          $this->size = $size;
        }
        // 實作父類別的狗叫 function
        public function Bark(){
          echo "狗叫...但小聲....";
          //呼叫父類別的 dogBark()
        }
      }
      ?>
      
    • 利用 demo2.php 來使用上述程式:
      <?php
        include "Poodle.php";
      
        $mydog = new Poodle("Windy","白色","貴賓狗",30);
        //修改此行
        echo $mydog->Bark();
      ?>
      

本章練習:
  • 修改 dog.php 檔案,使用 Bark.php 介面程式
  • 修改 cat.php 檔案,將 cat 類別抽象化,並且使用 Bark.php 介面程式

2021年3月12日 星期五

PHP 物件封裝與繼承方法

設定目標:
  • 了解物件導向封裝與繼承的概念
  • 了解 PHP 使用封裝與繼承的方法

物件封裝概念與方法
  1. 封裝 (Encapsulation)的目的 :
    • 用於限制物件資源的使用
    • 存取權限分類:
      • public : 可以在任何地方存取該物件資源!若沒指定,PHP 會指定其為預設值!
      • protected : 可以在自身類別和子類別中存取!
      • private : 只能在自身類別中存取!
    • 例:MyDog.php
      <?php
        class MyDog {
          // 定義 dog 的種類「屬性」,並設定「公開」權限
          public $raise = "柴犬";
          // 定義 dog 的年紀「屬性」,並設定「保護」權限
          protected $age = 5;
          // 定義 dog 的名字「屬性」,並設定「私人」權限
          private $name = "Peter";
          
          // 定義取得 dog 屬性值取得的「方法」, 並設定「公開」權限
          public function getPara(){
            echo "MyDog->raise : ".$this->raise."<br />";
            echo "MyDog->age : ".$this->age."<br />";
            echo "MyDog->name : ".$this->name."<br />";
          }
         } 
          // 產生實際物件
          $mydog = new MyDog();
          // 利用 getPara() 方法,取出實際物件的屬性值
          $mydog->getPara();
          // 直接使用物件,取出實際物件的屬性值,並且與 getPara() 方法對照
          echo "mydog->raise : ".$mydog->raise."<br />";
          echo "mydog->age : ".$mydog->age."<br />";
          echo "mydog->name : ".$mydog->name."<br />";
      ?>
      
  2. 建構子(constructor)與解建構子(destructor)
    • 建構子 : 用於建立物件時,一併設定好物件相關屬性與設定!
    • 解建構子 : 用於消除物件時,一併解除物件相關屬性與設定!通常放於類別最後面,程式會自動執行,不需要特別呼叫!
    • 例 : 修改先前的 dog.php 程式
      <?php
      class dog {
         // 設定狗的屬性
         public $name;
         public $color;
         public $style;
         
         //設定建構子
         public function __construct($name,$color,$style){
           $this->name = $name;
           $this->color = $color;
           $this->style = $style;
         }
      
         public function dogRun(){
           echo "狗狗跑步中...";
         }
      
         public function dogBark(){
           echo "狗叫...";
         }
      
         public function __destruct(){
           echo "狗狗回家了...";
         }
      }
      ?>
      
    • 利用 demo.php 來使用上述 dog.php 程式:
      <?php
          include "dog.php";
          $myDog = new dog("來福","白色","台狗土狗");
          $myDog->dogRun();
      ?>
      
物件繼承觀念與應用
  1. 繼承(extends)
    • 作用
      • 避免寫出重複的程式碼!
      • 依據需求,重複利用相同程式碼,做出功能不同的程式!
      • 子類別繼承父類別的屬性與方法,免去定義相同功能!
      • 必要時,子類別除了可以定義自己的屬性與方法,也可改寫父類別的屬性與方法!
      • 語法格式 :
        class 類別名稱 {
        class 子類別名稱 extends 父類別名稱 {
          可執行的程式;
        }
        
      • 範例 : 牧羊犬是狗的一個子類別 Shepherd.php
        <?php
          // 引入 dog 類別
          include "dog.php";
          // 定義牧羊犬 Shepherd 是 狗 dog 的子類別
          class Shepherd extends dog{
             // 定義子類別需要的屬性
             protected $age;
        
             public function __construct($name,$color,$style,$age){
               // 繼承父類別的屬性
               parent::__construct($name,$color,$style);
               $this->name = $name;
               $this->color = $color;
               $this->style = $style;
               $this->age = $age;
              }
             // 定義子類別的方法 
             public function doWork(){
               echo "趕羊..."."
        "; } // 覆寫(override)解構子 public function __destruct(){ echo "趕羊到家了"; } } ?>
      • 利用 demo1.php 來使用上述 Shepherd.php 程式:
        <?php
          include  "Shepherd.php";
          $mydog = new Shepherd("peter","棕色","牧羊犬",10);
          echo $mydog->name."
        "; echo $mydog->color."
        "; echo $mydog->style."
        "; echo $mydog->doWork()."
        "; //子類別未改寫父類別的方法 echo $mydog->dogRun()."
        "; ?>
  2. 覆寫(override)
    • 作用  
      • 子類別需要改寫父類別中,相同的方法名稱時!
      • 覆寫後,仍可以呼叫父類別中相同的方法!
    • 範例 : Poodle.php
      <?php
      include "dog.php";
      
      class Poodle extends dog{
        protected $size;
      
        public function __construct($name,$color,$style,$size){
          parent::__construct($name,$color,$style);
          $this->size = $size;
        }
        // 覆寫狗叫的 function
        public function dogBark(){
          echo "狗叫...但小聲....";
          //呼叫父類別的 dogBark()
          parent::dogBark();
        }
      }
      ?>
      
    • 利用 demo2.php 來使用上述 Poodle.php 程式:
      <?php
        include "Poodle.php";
      
        $mydog = new Poodle("Windy","白色","貴賓狗",30);
        echo $mydog->dogBark();
      ?>
      

本章練習:
  • 寫兩支程式褲子與上衣,表述其繼承衣服的類別,並計算分別購買10件的費用!

PHP 類別宣告與物件使用方式

設定目標:
  • 了解基本物件導向觀念與應用
  • 了解 PHP 類別與物件的使用方式

基本物件導向觀念
  1. 物件導向的目的 :
    • 增加程式的重複利用性
    • 減少重複撰寫程式
    • 增加程式可擴充及延展性
    • 增加開發程式的靈活性
基本物件導向觀念
  1. 類別與物件 (Class &  Object)
    • 類別 : 定義物件的內容!其包含類別的函數與變數!
      • 函數 : 類別的方法
      • 變數 : 類別的屬性
      • 語法格式 :
        class 類別名稱 {
          // 設定變數
          public 變數名稱;
          .....
          // 設定函數
          public function 函數名稱(參數1,參數2,....){
            // 可以執行程式的區塊
          }
        }
        
      • 範例 : dog.php
        <?php
          class dog {
            // 定義 dog 的年紀「屬性」
            public $age;
            // 定義取得 dog 年紀屬性值的「方法」
            public function getAge(){
              return $this->age;
            }
          }
        ?>
        
      • 「->」: 代表呼叫物件的屬性或方法名稱
      • this : 表示「這個物件」自己
    • 物件 : 實際使用的程式碼,由類別實例化而來
      • 語法格式 :
        變數名稱 = new 類別名稱;
        
      • 範例 : demo.php
        <?php
            include "dog.php";
            $mydog = new dog();
            $mydog->age = 10;
            echo "我的狗年紀 : ".$mydog->getAge();
        ?>
        

本章練習:
  • 寫一支有關於衣服的類別,並計算購買10件衣服的費用!