想學 PHP,卻被 $、大括號和一長串英文函數嚇到?先別急著關掉分頁,PHP 不會因為你喝咖啡喝得慢就罷工。這篇會用小範例帶你從輸出文字、變數、條件判斷與迴圈,一路走到陣列、函數和生成器。
讀完後,你應該能看懂基本 PHP 程式,知道每個語法在做什麼,也能自己動手改出幾個小練習。重點不是把整本手冊背下來,而是建立一張之後查文件時看得懂的地圖。
先認識 PHP 程式
PHP 是在伺服器端執行的腳本語言,常用來產生動態網頁內容。瀏覽器通常只會收到 PHP 執行後的結果,不會直接看到伺服器上的 PHP 原始碼。
開始標籤與結束標籤
PHP 程式通常以 <?php 開始。若檔案全部都是 PHP,結束標籤 ?> 可以省略;這能避免檔案結尾不小心多出空白,進而干擾標頭或其他輸出。
<?php
echo 'Hello, PHP!';
PHP 除了能輸出純文字,也可以和 HTML 混用:
<!doctype html>
<html lang="zh-Hant">
<body>
<h1><?php echo '今天也要好好寫程式'; ?></h1>
</body>
</html>echo、print 與註解
echo 和 print 都能輸出內容。echo 可以接受多個引數;print 只接受一個引數,而且會回傳 1。一般輸出文字時,使用 echo 就很足夠,不必為了選邊站讓咖啡冷掉。
<?php
echo 'PHP ', '入門';
print ',先從小範例開始。';
// 這是單行註解。
/*
* 這是多行註解。
* 註解不會被 PHP 執行。
*/
變數與資料類型
變數命名
PHP 變數以 $ 開頭,名稱必須以字母或底線開頭,之後可以接字母、數字或底線。PHP 變數名稱區分大小寫,所以 $name 和 $Name 是兩個不同的變數;這種差異不大,卻很會讓除錯時間變長。
<?php
$name = '小明';
$coffeeCount = 2;
$_note = '變數名稱可以底線開頭';
常見資料類型
初學時最常遇到的類型包括整數 int、浮點數 float、字串 string、布林值 bool、陣列 array、物件 object、null 與資源 resource。使用變數前,不必先宣告它的類型;但在較大型的程式中,明確的型別宣告通常更容易維護。
<?php
$quantity = 3; // int
$price = 49.5; // float
$title = 'PHP 入門'; // string
$isPublished = true; // bool
$keywords = ['php', 'web']; // array
$nothing = null; // null
作用域與超全域變數
變數的作用域決定它在哪裡可用:
- 函數外宣告的變數屬於全域作用域。
- 函數內宣告的變數屬於區域作用域,函數結束後就不能直接從外部使用。
- 函數內的
static變數會在多次呼叫之間保留值。
雖然可以在函數內使用 global 讀取全域變數,但傳遞參數通常更清楚,也較容易測試。全域變數像是把所有東西都放在客廳桌上:找得到,但久了真的很難整理。
PHP 也提供超全域變數,例如 $_GET、$_POST、$_SESSION、$_COOKIE 與 $_SERVER。它們在不同作用域都能使用,但「能直接使用」不代表「可以直接信任」。
<?php
$name = $_GET['name'] ?? '訪客';
$safeName = htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
echo "你好,{$safeName}!";
輸入資料應先驗證,再依輸出情境進行處理。上例用 htmlspecialchars() 輸出 HTML 文字,可以降低未處理輸入造成 XSS 的風險;若資料要存進資料庫,則應使用資料庫擴充套件提供的參數化查詢,不要把字串直接拼進 SQL。
條件判斷與運算子
if、elseif 與 else
條件判斷讓程式可以依資料做不同決定。if 條件成立時執行第一段;不成立時,PHP 會繼續檢查 elseif,最後才執行 else。
<?php
$score = 85;
if ($score >= 90) {
echo '優秀';
} elseif ($score >= 60) {
echo '及格,繼續加油';
} else {
echo '再練習一次';
}
比較與邏輯運算子
== 只比較值,可能觸發型別轉換;=== 同時比較值與型別。除非你確實需要寬鬆比較,否則通常優先使用 === 與 !==。
常用邏輯運算子包括:&&(而且)、||(或者)以及 !(反轉布林值)。
<?php
$age = 20;
$hasTicket = true;
if ($age >= 18 && $hasTicket === true) {
echo '可以入場';
}
switch
當同一個值需要和多個固定選項比較時,switch 可以讓程式更容易閱讀。每個 case 通常要用 break 結束;漏寫時會繼續執行下一個 case,這種「順便多做一點」通常不是驚喜。
<?php
$day = 'Monday';
switch ($day) {
case 'Monday':
echo '星期一';
break;
case 'Friday':
echo '星期五';
break;
default:
echo '其他日子';
}
迴圈:讓重複工作交給電腦
for、while 與 do...while
知道大致重複次數時,可以用 for;只知道「條件成立就繼續」時,可以用 while。do...while 會先執行一次內容,再檢查條件。
<?php
for ($i = 1; $i <= 3; $i++) {
echo "第 {$i} 次\n";
}
$count = 0;
while ($count < 3) {
$count++;
}
do {
echo '至少執行一次';
} while (false);
foreach、break 與 continue
foreach 適合逐一處理陣列元素。需要索引或鍵和值時,可以同時寫成 $key => $value。continue 跳過本輪,break 則離開整個迴圈。
<?php
$colors = ['紅', '綠', '藍'];
foreach ($colors as $index => $color) {
if ($color === '綠') {
continue;
}
echo "{$index}: {$color}\n";
}
陣列
PHP 的陣列同時具備有序列表與關聯式映射的用途。數值陣列通常從索引 0 開始;關聯陣列則使用有意義的鍵名。
<?php
$fruits = ['蘋果', '香蕉'];
$fruits[] = '芒果';
$user = [
'name' => '小明',
'email' => 'ming@example.com',
];
echo $user['name'];
unset() 可以移除元素,sort() 會以升冪排序數值索引陣列;排序函數各自對索引與鍵名有不同影響,使用前要先看文件,不要讓水果在陣列裡突然失去身份證。
foreach 與陣列函數
array_filter() 會保留回呼函數判定為真的元素,array_map() 則把回呼函數套用到每個元素。這兩個函數很適合把「篩選」和「轉換」寫得清楚。
<?php
$numbers = [1, 2, 3, 4, 5];
$evenNumbers = array_filter(
$numbers,
fn (int $number): bool => $number % 2 === 0
);
$squares = array_map(
fn (int $number): int => $number * $number,
$numbers
);
其他常見工具還有 array_merge()(合併)、array_slice()(取出一段)以及 array_diff()、array_intersect()(比較差異或交集)。使用這些函數前,先確認它們如何處理數值索引與重複值。
函數:把重複工作包起來
參數與回傳值
函數把一段可重複使用的邏輯包起來。參數是輸入,return 是輸出;好的函數通常有清楚的名稱,也不偷偷修改外部狀態。
<?php
function greet(string $name): string
{
return "你好,{$name}!";
}
echo greet('PHP');
匿名函數與閉包
匿名函數沒有固定名稱,常作為 array_map() 等函數的回呼。它也可以用 use 捕捉建立當下作用域的變數。
<?php
$prefix = 'Hi';
$greet = function (string $name) use ($prefix): string {
return "{$prefix}, {$name}!";
};
echo $greet('PHP');
PHP 也支援短箭頭函數 fn,適合只有一個表達式的簡短回呼;若邏輯需要多行,普通匿名函數通常更好讀。
型別宣告與嚴格模式
函數可以為參數與回傳值加入型別。declare(strict_types=1); 必須放在檔案最前面(在 <?php 後),可讓該檔案中呼叫函數時的純量型別檢查採取嚴格模式。
<?php
declare(strict_types=1);
function add(int $a, int $b): int
{
return $a + $b;
}
echo add(5, 5);
型別宣告能提早暴露錯誤,但不能取代輸入驗證。來自表單或 API 的資料仍然要先檢查、轉換,必要時再拒絕不符合預期的值。
可變參數與參照
...$numbers 可以接收任意數量的引數,函數內會得到一個陣列。參數前加 & 則是以參照傳遞,函數可以直接修改呼叫端的變數;這是刻意的行為,使用時要讓讀者一眼看出來。
<?php
function sum(int ...$numbers): int
{
return array_sum($numbers);
}
function addExclamation(string &$text): void
{
$text .= '!';
}
$message = '完成';
addExclamation($message);
echo sum(1, 2, 3);
生成器:需要時才產生資料
生成器使用 yield 一次產生一個值。呼叫生成器函數時,不會立刻把所有結果放進陣列;搭配 foreach 逐項讀取時,適合處理不想一次載入記憶體的資料。
<?php
function numbers(int $max): Generator
{
for ($i = 0; $i < $max; $i++) {
yield $i;
}
}
foreach (numbers(3) as $number) {
echo $number . PHP_EOL;
}
這不代表生成器自動讓所有程式變快,也不代表資料庫查詢就能無限吃。它只是提供「逐步取得值」的迭代方式;實際效益仍要看資料來源和程式的瓶頸。
10 個小練習
不要只看範例點頭,手指動起來才算真的學會。你可以依序完成:
- 輸出你的名字與今天的日期。
- 宣告商品名稱、價格與數量,計算小計。
- 判斷一個數字是正數、負數或零。
- 用
switch根據星期顯示工作日或休息日。 - 用
for輸出 1 到 10 的偶數。 - 用
foreach計算陣列中的數字總和。 - 將一個關聯陣列安全地輸出成 HTML。
- 用
array_filter()找出價格低於 100 的商品。 - 寫一個有參數型別與回傳型別的折扣函數。
- 用生成器逐一產生 1 到 100 的數字。
遇到錯誤時,先讀錯誤訊息,再縮小問題範圍;不要一看到紅字就把整杯咖啡灌進鍵盤。完成這 10 題後,可以接著學習類別與物件、例外處理、資料庫、HTTP、測試與框架。PHP 的世界很大,但你現在已經有一張能走路的地圖。

