National Taiwan University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

1

Local AI

--

Uedu Code

--

台灣大學 AQI 67 24°C PM2.5 11
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 03

變數與資料型別

$ 變數、八種資料型別、型別轉換、常數,以及 isset、empty 與 ??
Interaction實作 30 minute(s)

Learning Objectives

  • 依命名規則建立變數,說明 PHP 是動態型別:變數的型別由目前存放的值決定
  • 分辨 int、float、string、bool 與 null,用 var_dump、get_debug_type 檢查型別
  • 說明整數超過 PHP_INT_MAX 會變成浮點數、浮點數有精度限制(0.1 + 0.2)
  • 預測自動型別轉換的結果,使用 (int)、(float)、(string)、(bool) 與 intval 強制轉換,並列出哪些值會被當成 false
  • 用 define 與 const 定義常數,用 isset、empty 與 ?? 處理可能不存在的變數

程式要記住東西,就需要變數

程式處理的每一筆資料(使用者的名字、商品價格、是否已登入)都要先存起來才能使用,存放的地方就是變數(variable)。 每個值都有型別(type):20 是整數、172.5 是浮點數、'Amy' 是字串。

PHP 是動態型別的語言:變數不用事先宣告型別,存進什麼值,它就是什麼型別;同一個變數之後也可以換成另一種型別的值。 這很方便,但也代表 PHP 常常會自動轉換型別,例如把字串 '5' 當成數字 5 來計算。 這一課要弄清楚:PHP 有哪些型別、什麼時候會自動轉換、轉換的規則是什麼。這些規則是很多 PHP 程式錯誤的來源。

變數的寫法與命名規則

$score = 90;          // 建立變數 $score,把 90 存進去(指派)
$score = 95;          // 換成新的值
$total = $score + 5;  // 讀取變數的值來計算
規則 範例
以 $ 開頭,後面接名稱 $name
名稱的第一個字元是英文字母或底線,不能是數字 $_count 可以,$1st 不行
之後可以是英文字母、數字、底線 $student_2
區分大小寫 $score 和 $Score 是不同的變數
不能用 $this(物件裡有特別用途,第 14 課)

PHP 也允許中文等非英文字元當變數名稱($分數),但會讓字串插值容易出錯,也不方便和別人合作,建議一律用英文。 多個英文字組成的名稱,常見兩種寫法:$studentName(小駝峰)或 $student_name(底線),同一個專案選一種用到底。 名稱要說明內容:$price 比 $p 好,$isLoggedIn 一看就知道是是非題。

PHP 的資料型別

PHP 的值常被分成 8 種型別:

分類 型別 例子 說明
純量 int(整數) 42、-7、0 沒有小數點的數字
純量 float(浮點數) 3.14、2.0、1.5e3 有小數點或用科學記號寫的數字
純量 string(字串) 'Amy'、"你好" 一串文字
純量 bool(布林) true、false 只有真、假兩個值
複合 array(陣列) [1, 2, 3] 一組值,第 08 課
複合 object(物件) new DateTime() 第 14 課
特殊 null null 「沒有值」;只有這一個值
特殊 resource(資源) fopen() 的回傳值 開啟中的檔案等外部資源,第 12 課

這一課專注在純量型別與 null。檢查型別的三種方法:

寫法 結果 用途
var_dump($x) int(20)、string(3) "Amy" 除錯時最常用:同時看到型別與值
get_debug_type($x) "int"、"float"、"null" PHP 8.0 新增,回傳標準的型別名稱
gettype($x) "integer"、"double"、"NULL" 舊函式;名稱是歷史寫法(浮點數回傳 "double")

echo 不適合用來檢查型別:echo false; 什麼都不印,echo null; 也是,你分不出差別。

五種值與 var_dump

左邊的變數區會顯示每個變數目前的值:浮點數一定有小數點,字串有引號,true、null 直接顯示。看第 8 行 var_dump 的輸出格式,以及最後 $age 從整數變成字串。

整數與浮點數

整數有範圍限制。現在的伺服器幾乎都是 64 位元,最大值是常數 PHP_INT_MAX(9223372036854775807,約 9.2 × 10¹⁸), 最小值是 PHP_INT_MIN。計算結果超過範圍時,PHP 不會報錯,而是自動變成浮點數,精度也跟著下降。

整數有幾種寫法:

寫法 意思 值
1_000_000 底線只是方便閱讀 1000000
0x1F 十六進位 31
0b101 二進位 5
0o17 或 017 八進位(0o 寫法是 PHP 8.1 加入的) 15

浮點數用二進位表示小數,很多十進位小數(例如 0.1)沒辦法精確表示,只能存一個非常接近的值, 所以 0.1 + 0.2 實際上是 0.30000000000000004。echo 只顯示 14 位有效數字,看起來是 0.3;var_dump 會顯示完整的值。 不要用 == 比較兩個浮點數,改成比較差距夠不夠小,或先 round() 再比較。金額計算可以改用整數(以「分」為單位)。

整數溢位與浮點數精度

第 4 行讓最大的整數再加 1:結果不是錯誤,而是變成浮點數。第 8、9 行用兩種方式輸出同一個 $sum,比較 echo 與 var_dump 的差別。

字串:單引號與雙引號

單引號 '…' 雙引號 "…"
變數 不替換:'$name' 就是 $name 這幾個字 替換成值:"Hi $name"
跳脫字元 只認得 \' 與 \\ \n(換行)、\t(Tab)、\"、\$、\\
適合 固定的文字 需要放變數或換行的文字

雙引號字串裡放變數,建議一律寫成 {$name}:大括號清楚標出變數名稱到哪裡結束。 變數後面緊接中文或英文字母時,一定要加大括號,否則 PHP 會把後面的字也當成變數名稱的一部分。 另外,"${name}" 這種寫法從 PHP 8.2 起被標為棄用,不要使用。字串的各種操作在第 09 課介紹。

型別轉換

自動轉換(type juggling):運算子需要什麼型別,PHP 就把值轉成那個型別。

情況 例子 結果
算術運算遇到數字字串 '5' + 3 8(int)
字串串接遇到數字 'NT$' . 100 'NT$100'(string)
開頭是數字、後面有其他字的字串 '12abc' + 1 13,並出現 Warning: A non-numeric value encountered
完全不是數字的字串 'abc' + 1 TypeError,程式停止(PHP 8 起)
if 等需要真假的地方 if ('0') 轉成 bool,見下一節

強制轉換(type casting):在值前面加上 (型別),自己決定要轉成什麼。

寫法 規則 例子
(int)、intval() 取開頭的數字部分,沒有就是 0;浮點數直接捨去小數(不是四捨五入) (int) '12abc' → 12、(int) 'abc' → 0、(int) 3.99 → 3
(float)、floatval() 取開頭的數字部分 (float) '3.14 公尺' → 3.14
(string)、strval() 數字轉成文字;true → '1'、false 與 null → '' (string) 2.0 → '2'
(bool)、boolval() 見下一節的「假值」 (bool) '0' → false

強制轉換不會出現警告,所以 (int) 適合用在「確定要一個整數,不合格就當 0」的地方。 使用者從表單送來的資料一律是字串(第 11 課),計算前常常要先轉換。

自動轉換與強制轉換

前三組是 PHP 自動轉換,第 10 到 12 行是強制轉換。最後一行的 '12abc' + 1 會算出結果,但 PHP 同時印出 Warning 提醒你這個字串不完全是數字。

想一想:型別與轉換

1.

下面的程式會印出什麼?

<?php
$x = '10';
$y = $x + 5;
var_dump($y);
$z = $x . 5;
var_dump($z);
2.

下面的程式會印出什麼?

<?php
echo (int) '3.9kg' + (int) 2.9;
3.

下面的程式執行的結果是什麼?

<?php
$n = 'abc' + 1;
echo $n;
第 1 次作答

哪些值會被當成 false

if、while、!、&& 這些地方需要一個真假值,PHP 會把任何值自動轉成 bool。只有下面這些值是 false,其他全部是 true:

值 說明
false 布林的假
0、0.0(以及 -0.0) 整數零、浮點數零
'' 空字串
'0' 只有一個字元 0 的字串
null 沒有值(包括還沒定義的變數)
[] 空陣列

容易誤會的:'0.0'、' '(一個空白)、'false'(五個字母的字串)、-1 都是 true。 字串 '0' 是 false 這一點特別要小心:使用者在表單輸入 0,if ($input) 會把它當成「沒有輸入」。

轉成布林值

第 3、4 行的六個值都是 false;第 7 行的四個值看起來像「假」,其實都是 true。最後的 if 示範字串 '0' 造成的問題。

常數

常數(constant)是設定之後就不能改變的值,適合放「整個程式都用到、不會變」的設定,例如網站名稱、分數上限、稅率。

define('SITE_NAME', 'Uedu CodeLab');   // 用函式定義,名稱是字串
const MAX_SCORE = 100;                 // 用關鍵字定義
const PASS_SCORE = MAX_SCORE * 0.6;    // 可以用其他常數計算

echo SITE_NAME, PHP_EOL;               // Uedu CodeLab
echo '及格分數:', PASS_SCORE, PHP_EOL; // 及格分數:60
echo "MAX_SCORE\n";                    // 字串裡不會替換,印出 MAX_SCORE
define('SITE_NAME', '別的名稱');        // Warning: Constant SITE_NAME already defined
  • 常數名稱沒有 $,慣例全部大寫、用底線分隔字
  • 常數名稱區分大小寫;可以在程式的任何地方使用,包括函式裡面
  • 已經定義的常數不能重新定義或修改:再 define 一次會出現 Warning,值不變
  • const 必須寫在最外層(不能放在 if 或函式裡),define() 可以放在任何地方,例如依條件決定值
  • 常數不會在雙引號字串裡被替換,要用逗號或 . 接起來
  • defined('NAME') 檢查常數是否已經定義

PHP 有很多預定義常數:

常數 意思
PHP_EOL 這個作業系統的換行字元(Linux 是 "\n")
PHP_INT_MAX、PHP_INT_MIN 整數的最大值、最小值
PHP_VERSION 目前 PHP 的版本字串
M_PI 圓周率
E_ALL、E_WARNING 錯誤的種類(設定錯誤回報時用)

變數不存在怎麼辦:isset、empty 與 ??

讀取一個沒有定義過的變數,PHP 8 會印出警告並當成 null 繼續執行:

Warning: Undefined variable $nothing in /var/www/html/index.php on line 11

警告代表程式有地方沒想清楚。資料可能不存在時(例如使用者沒有填某個欄位),先檢查再使用:

寫法 什麼時候是 true 變數不存在時
isset($x) 變數存在而且不是 null false,不會出現警告
empty($x) 變數不存在,或值是假值(0、''、'0'、null、[]、false) true,不會出現警告
$x ?? '預設值' 不是運算式,是取值:$x 存在且不是 null 就用 $x,否則用右邊的值 用右邊的值,不會出現警告

?? 叫做 null 合併運算子,只看「是不是 null 或不存在」:$score = 0 時,$score ?? 60 仍然是 0。 empty() 則會把 0 也當成「空」,所以不適合用來檢查數字是否有填寫。

變數的變數:$$name 會先取出 $name 的值(例如 'score'),再把它當成變數名稱,也就是 $score。 這種寫法讓程式難以閱讀,實務上幾乎都用陣列取代(第 08 課),知道有這種寫法即可。

isset、empty、?? 與未定義的變數

$nothing 和 $nickname 從來沒有定義過。第 6、7、9 行用 isset、empty、?? 檢查它們,不會出現警告;第 11 行直接在字串裡使用 $nothing,就出現 Warning。

想一想:假值與 ??

1.

下面的程式會印出什麼?

<?php
var_dump((bool) '0', (bool) '0.0', (bool) []);
2.

下面的程式會印出什麼?

<?php
$qty = 0;
$note = null;
echo $qty ?? 10, ' ', $note ?? '無', ' ';
var_dump(empty($qty));
3.

下面的程式會印出什麼?

<?php
define('RATE', 0.05);
const TAX = 'RATE';
echo "RATE ", RATE * 100, ' ', TAX;
第 1 次作答

動手做:把字串轉成數字再計算

從表單收到的資料都是字串。請完成程式:定義運費常數 SHIPPING 為 60;把數量轉成整數、單價轉成浮點數、折扣轉成整數(折扣是空字串,轉成整數就是 0)。執行後應該印出:

數量:int(3)
單價:float(120.5)
折扣:int(0)
總計:421.5
你的輸出
預期輸出

重點回顧

  • 變數以 $ 開頭,名稱以英文字母或底線開頭、區分大小寫;PHP 是動態型別,型別由目前的值決定
  • 純量型別:int、float、string、bool,加上表示「沒有值」的 null;陣列與物件在第 08、14 課
  • 檢查型別用 var_dump() 或 get_debug_type();gettype() 對浮點數回傳歷史名稱 "double"
  • 整數超過 PHP_INT_MAX 會變成浮點數;浮點數有誤差,0.1 + 0.2 == 0.3 是 false,不要用 == 比較浮點數
  • 數字字串在算術中自動轉成數字;'12abc' + 1 會有 Warning,'abc' + 1 在 PHP 8 丟出 TypeError
  • (int) 取開頭的數字、捨去小數;強制轉換不會出現警告
  • 假值只有:false、0、0.0、''、'0'、null、[];'0.0'、' '、'false' 都是 true
  • 常數用 define() 或 const 定義,沒有 $、慣例全大寫、不能修改;PHP_EOL、PHP_INT_MAX 是預定義常數
  • 讀取未定義的變數會出現 Warning;先用 isset()、empty() 檢查,或用 $x ?? 預設值 取值
這一課完成了!
Next lesson:運算子
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。