iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 5
8
Modern Web

寫給朋友的 PHP 從 0 到 100 實戰教程系列 第 5

Day 5. PHP教學: 開始架設自己的遊戲攻略網站 (class 物件篇)

昨天的題目,有人想知道作法,就在這邊解答吧!來分析一下上個月跟這個月的訂單差異在哪?

$order_receive['1221001'] = 0;
$order_receive['1221008'] = 0;
$order_receive['1130199'] = 200; // 發現上個月訂單編號規則是 11/30 的第 199 單

所以我們可以用一個小迴圈來分析這個 order_id 把陣列的 key 字串拆成年月日跟最後三碼

foreach( $order_receive as $key => $val){
   // $key 隨著迴圈跑起來就會是 1221001, 1221008, 1130199
   $month = substr($key, 0, 2); // 取得從第 0 個字開始,往後抓 2 位 所以是 12
   $day   = substr($key, 2, 2); // 取得從第 2 個字開始,往後抓 2 位 所以是 21
   $count = substr($key, 4, 3); // 取得從第 4 個字開始,往後抓 3 位 所以是 001
   
   if($month == '11')continue; // 從頭開始,不執行下方的工作
   
   // ...略過針對 12 月的事情...
}

正文開始

Why
因為你不想在看無聊基本教學!所以我們直接來實戰吧!
就拿現在很紅的遊戲『傳說對決』來當例子,
一步一步教你怎麼做一個英雄要怎麼玩的攻略站

How
那要怎麼開始呢?
首先我們想一下以往看過的遊戲攻略網站有哪些東西
想像有個首頁:這頁要顯示全部英雄角色,有他們的名字
點角色名稱進去有他的四招技能說明跟一篇文章教學
可以再跳回首頁或是下一個英雄。

所以我們最主要的工作就是告訴新玩家『英雄』要怎麼玩
這個『英雄』有『名字』、『攻防數值』、『技能』跟『玩法教學文章』要展示對吧

我們很直接地想到可以用一些變數來描述這個英雄

$hero_name          // 角色的名稱
$hero_stats_hp      // 角色生命力數值
$hero_stats_mp      // 角色法力數值
$hero_stats_atk     // 角色攻擊力數值
$hero_stats_def     // 角色防禦力數值
$hero_skill_1       // 角色第一招技能
$hero_skill_2       // 角色第二招技能
$hero_skill_3       // 角色第三招技能
$hero_skill_4       // 角色第四招技能
$hero_article       // 角色玩法文章

這時候有沒有人注意到其實有很多重複的地方,像是 hero 這個字每一行都重複了
如果有一天鳥事發生,要把 英雄 Hero 這個詞換成,英雄聯盟的英雄用字 Champion
就會發生慘案,需要你手動改幾百頁裡面一堆用字的鳥事
如果一個不小心漏掉就等於那段整個功能壞掉。
所以會想要盡量把重複的事情,精簡化、朝容易使用的方向調整。

為了避免重複的事情,會想用一個結構去描述這些『東西』
我們可以觀察上面這些變數有一些共同點

  • 其實都是描述同一個『英雄』
  • 其實生命力、攻擊力等等有四個都是『數值』
  • 技能有四個重複了

我們可以用一個 PHP 語法來描述『英雄』這個東西

class Hero {
    public $name;          // 角色的名稱
    public $stats_hp;      // 角色生命力數值
    public $stats_mp;      // 角色法力數值
    public $stats_atk;     // 角色攻擊力數值
    public $stats_def;     // 角色防禦力數值
    public $skill_1;       // 角色第一招技能
    public $skill_2;       // 角色第二招技能
    public $skill_3;       // 角色第三招技能
    public $skill_4;       // 角色第四招技能
    public $article;       // 角色玩法文章
}

What

  • class 代表的是『說明書』,用來說明這個「英雄」要有哪些變數資料
  • class 也叫做『類別』,從主管或同事嘴裡冒出這個字別嚇到,就是『說明書』而已
  • 所以這語法可以「說明」這個『英雄』必需要有哪些資料
  • 我們成功把 hero 通通都抓出來放到最上面 class 的右邊當成 class name
  • public 是指外部可以直接透過 -> 這個語法取用,可以看下面例子
  • 普遍來說,不推薦設成 public ,而會用 private (私有的)差在哪,想知道可以搜尋一下

How 如何使用這個 class Hero 呢?
我們需要依照說明書把英雄組裝起來才能開始用它
來看看語法:

$heroBox = new Hero();
// 這行的意思是我要把『英雄』依照『class 說明書』,
// 組裝起來成為『object 物件』放到變數 $heroBox 裡面
$heroBox->name = "Valhein"; // 設定角色名稱為 凡恩
$heroBox->stats_hp = 100;   // 設定生命力數值為 100
$heroBox->stats_mp = 80;    // 設定法力數值為 80
$heroBox->stats_akt = 40;   // 設定攻擊力數值為 40
$heroBox->stats_def = 20;   // 設定防禦力數值為 20
// 這幾行的意思都是把 資料塞到 這個物件裡面
//... 下略
  • 這個變數 $heroBox 可以任意改名字因為他只是個箱子 可以改叫 $hero 或 $box 都可以
  • 後方的 new Hero(); 就不能亂改了, new 是把『說明書』組裝成『物件』的語法 Hero 是剛剛的 class
  • $heroBox->name 這邊有個 -> 意思是『指向』這個『物件』肚子裡面的變數 name 的意思
    順帶一題,如果改變數名字把 heroBox 改 hero,使用起來會像下面例子:
$hero = new Hero();
$hero->name = "Valhein"; // 設定角色名稱為 凡恩
$hero->stats_hp = 100;   // 設定生命力數值為 100
$hero->stats_mp = 80;    // 設定法力數值為 80
$hero->stats_akt = 40;   // 設定攻擊力數值為 40
$hero->stats_def = 20;   // 設定防禦力數值為 20
$hero->skill_1;       // 角色第一招技能
$hero->skill_2;       // 角色第二招技能
$hero->skill_3;       // 角色第三招技能
$hero->skill_4;       // 角色第四招技能
$hero->article;       // 角色玩法文章

這樣對於『class 類別』跟『object 物件』的概念是不是清楚多了呢?

再進階一點,我們也看到很多的 stats 跟 skill 這個可不可以也抓出來呢?
沒錯!為了同一個目標,這樣設計是可以的:設計圖內是可以再放設計圖。

首先我們要另外開一個新的 stats 設計圖(class 類別),並加到 hero 裡面

class Stats {
   public $hp;  // 生命值
   public $mp;  // 法力值
   public $atk; // 攻擊力
   public $def; // 防禦力
   public function __construct($sourceHp, $sourceMp,$sourceAtk, $sourceDef){
        $this->hp = $sourceHp; // 組裝時,把 生命力數值 傳進物件內
        $this->mp = $sourceMp; // 組裝時,把 法力數值 傳進物件內
        $this->atk = $sourceAtk; // 組裝時,把 攻擊力數值 傳進物件內
        $this->def = $sourceDef; // 組裝時,把 防禦力數值 傳進物件內
   }
}
class Skill {
   public $name;        // 技能名稱
   public $description; // 技能描述
   function __construct($sourceName, $sourceDescription){
        $this->name = $sourceName;
        $this->description = $sourceDescription;
   }
}
class Hero {
   public $name;    // 預備裝 角色名稱字串變數
   public $stats;   // 準備裝『數值物件』的變數
   public $skills;  // 準備裝『技能物件』的陣列變數
   public $article; // 預備來裝 教學文章 變數
   function __construct($sourceName, $sourceStats, $sourceSkills, $sourceArticle){
        $this->name = $sourceName;
        $this->stats = $sourceStats;
        $this->skills = $sourceSkills;
        $this->article = $sourceArticle;
   }
}
// 使用的方法是這樣
$sourceStats = new Stats(100, 80, 40, 20);
$sourceSkills[] = new Skill("獵手","...說明略...");
$sourceSkills[] = new Skill("血腥獵殺","...說明略...");
$sourceSkills[] = new Skill("送葬詛咒","...說明略...");
$sourceSkills[] = new Skill("水銀彈幕","...說明略...");
$sourceArticle = "文章略";
$hero = new Hero("凡恩",$sourceStats, $sourceSkills, $sourceArticle);
// 這樣就得到 一隻凡恩英雄物件(object)了,
// 亦可以這樣取出資料
echo $hero->stats->hp."\n";
echo $hero->stats->atk."\n";
echo $hero->skills[0]->name."\n";
echo $hero->article."\n";
  • 解釋一下新的東西 下面這行叫做『建構子』、或『建構式』
function __construct( /*這裏放傳進來的資料*/ ) {
   // 這裏放要執行的事情
}
  • 它是在組裝 class 說明書類別成為 object 物件時,必須先執行的事情
  • 這行 $this->name = $sourceName; 意思是把 new Hero("這裏的字串"); 轉存到物件內
  • 因為,物件內是不能直接使用外面變數的,內外不共通,一定要透過這個 -> 語法才能變更

今天講的結構概念稍微難一點,
的目標就是把很多相關的變數組合起來變成一個「精簡又易用」的物件
如果有看不懂的地方,歡迎留言告訴我。

下一篇會用最簡單的方式教會大家怎麼使用 PHP 連接資料庫,
讀取資料開始組裝這些英雄物件,秀到網頁上。

喜歡我的文章可以按個讚,也歡迎訂閱下一期教學文章,分享給想學程式的好朋友


上一篇
Day 4. PHP教學: 用迴圈解決重複無聊的工作
下一篇
Day 6. PHP教學: 用物件的方式連接MYSQL 資料庫 (含範例)
系列文
寫給朋友的 PHP 從 0 到 100 實戰教程30
1
murasaki1220
iT邦新手 5 級 ‧ 2018-09-25 22:20:37

菜鳥有問題:
文章裡提到『new: 把class(此處為Hero)組裝成object,放到變數(此處為$heroBox)裡』
不是很懂組裝的意思...
我的理解是class加上new之後會改變詞性(?),變成object,才可以放入變數使用,為日後的更動節省時間。
這樣理解對嗎?

很喜歡這樣的實例教學,知道學到的東西可以在實務上如何運用,
學起來特別有動力:)

看更多先前的回應...收起先前的回應...

class 有點像是設計圖 透過 new 指令會轉成實體物件 object 才能開始使用,而且可以不斷的 new 這個 class 變出很多各自獨立資料的物件 可以變出很多隻 Hero 各自有不同屬性

不懂可以再跟我說 我換個方法解釋 這地方我剛開始也是覺得腦袋被拍一下子完全不能接受XD

原來是設計圖到實體物件的概念,這樣我懂了XD
謝謝老師~

/images/emoticon/emoticon34.gif

0
s9771067
iT邦新手 5 級 ‧ 2018-12-13 18:26:51

感謝您如此生動地說明,第一次看還真有點需要思考,持續消化中……

想請問下方的最後兩行的註解,是否是筆誤呢?

$this->hp = $sourceHp; // 組裝時,把 生命力數值 傳進物件內
$this->mp = $sourceMp; // 組裝時,把 法力數值 傳進物件內
$this->atk = $sourceAtk; // 組裝時,把 法力數值 傳進物件內
$this->def = $sourceDef; // 組裝時,把 法力數值 傳進物件內

感謝您的教學文,讓人觀念變得很清楚!

ya 筆誤 我調整一下

0
stanley6933
iT邦新手 5 級 ‧ 2019-03-20 12:13:10

請問為何這段echo $hero->skills[0]->name."\n";
已經指出說要echo 技能中的第一個技能了,為何後面還要再加->name呢?

因為 $sourceSkills[] = new 技能
是把一個物件放到陣列裡面

所以會變成一串火車
[技能1]-[技能2]-[技能3]-[技能4]
skills[0]是第一節車廂指的是[技能1]
想要 echo 印出的是技能1(物件)的名字
所以要在物件後面加上 ->name
拿到 技能名字

我要留言

立即登入留言