cv.cm

編碼 · 程式語言

PHP 入門教學

閱讀約 8 分鐘

簡答

PHP 是專為網頁打造的伺服器端腳本語言:PHP 檔案在伺服器上執行,並將 HTML 或 JSON 傳送給瀏覽器。安裝 PHP 後,將 <?php echo "Hello, world"; 存成 hello.php 並執行 php hello.php,或用 php -S localhost:8000 啟動本機伺服器。核心概念包括以 $ 開頭的變數、靈活的陣列、帶有型別宣告的函式、類別、例外,以及安全處理使用者輸入。

開啟JSON 格式化

PHP 是什麼,用來做什麼

PHP 由 Rasmus Lerdorf 於 1994 年創造;現在這個名稱代表「PHP: Hypertext Preprocessor」。幾乎所有虛擬主機都能執行它,大量網站都由它驅動,包括 WordPress、Drupal 與維基百科使用的 MediaWiki。開發者用它建立內容網站、網路商店、REST API,並搭配 Laravel 與 Symfony 等框架開發完整的網頁應用程式。現代 PHP 8 擁有型別系統、JIT 編譯器、列舉、屬性(attribute),效能也遠勝舊版本。

安裝 PHP 並執行 Hello, world

從 php.net 或套件管理工具安裝 PHP(brew install php、sudo apt install php-cli,或 Windows 上的 XAMPP 這類整合套件),並用 php -v 確認。PHP 程式碼寫在 <?php 與可省略的結尾 ?> 標籤之間。

<?php
echo "Hello, world\n";
php hello.php
# Hello, world
php -S localhost:8000    # serve the current folder at http://localhost:8000

在只包含 PHP 程式碼的檔案中,請省略結尾的 ?> 標籤,以免意外把多餘的空白字元傳送給瀏覽器。

變數與基本型別

變數名稱以 $ 開頭。型別是動態的,但你可以宣告參數與回傳型別,而檔案開頭的 declare(strict_types=1); 會停止函式呼叫中的自動型別轉換。

型別範例說明
int$n = 42;多數系統上為 64 位元
float$x = 3.14;雙精度
string$s = "hi $name";雙引號會內插變數,單引號不會
bool$ok = true;不分大小寫的關鍵字
array$a = [1, 2];有序對應表:同時是 list 與字典
null$v = null;沒有值
<?php
$name = "Ada";
$count = 7;
echo "$name has $count items\n";        // Ada has 7 items
echo 'No $interpolation here' . "\n";   // No $interpolation here
echo intdiv($count, 2), " ", $count / 2, "\n";  // 3 3.5
var_dump((int) "12" + 1);                // int(13)

. 運算子用來連接字串;+ 只用於數字。

流程控制

<?php
$score = 72;
if ($score >= 90) {
    echo "A\n";
} elseif ($score >= 70) {
    echo "B\n";                   // B
} else {
    echo "C\n";
}

for ($i = 0; $i < 3; $i++) {
    echo $i, " ";                 // 0 1 2
}
echo "\n";

foreach (["apple", "pear"] as $fruit) {
    echo $fruit, "\n";
}

$kind = match ($day = "SAT") {   // match is strict and returns a value
    "SAT", "SUN" => "weekend",
    default => "weekday",
};
echo $kind, "\n";                 // weekend

match(PHP 8.0 起)以 === 比較,沒有任何分支符合時會拋出錯誤;舊的 switch 則是寬鬆比較,且沒有 break 時會繼續往下執行。

函式

<?php
declare(strict_types=1);

function greet(string $name, string $greeting = "Hello"): string
{
    return "$greeting, $name!";
}

echo greet("Lin"), "\n";                    // Hello, Lin!
echo greet(greeting: "Hi", name: "Lin"), "\n"; // Hi, Lin!  (named arguments)

$square = fn(int $x): int => $x * $x;       // arrow function
echo $square(5), "\n";                      // 25

function total(int ...$nums): int           // variadic
{
    return array_sum($nums);
}
echo total(1, 2, 3), "\n";                  // 6

招牌特色:陣列

PHP 陣列是一種靈活的型別,可以當作 list、字典、堆疊或佇列使用。鍵可以是整數或字串,並會保留插入順序。還有大量內建函式可以操作陣列。

<?php
$nums = [3, 1, 2];
$nums[] = 5;                       // append
sort($nums);
echo implode(", ", $nums), "\n";   // 1, 2, 3, 5

$ages = ["ann" => 31, "bob" => 25];
$ages["cy"] = 40;
foreach ($ages as $person => $age) {
    echo "$person is $age\n";
}
echo $ages["zed"] ?? 0, "\n";      // 0  (null coalescing)

$evens = array_filter($nums, fn($n) => $n % 2 === 0);
$squares = array_map(fn($n) => $n * $n, $nums);
echo json_encode(array_values($evens)), " ", json_encode($squares), "\n";  // [2] [1,4,9,25]
echo count($ages), " ", array_key_exists("bob", $ages) ? "yes" : "no", "\n"; // 3 yes

陣列在賦值時會被複製(寫入時複製),這與以控制代碼(handle)傳遞的物件不同。

類別、建構子提升與列舉

<?php
declare(strict_types=1);

enum Role: string
{
    case Admin = "admin";
    case Viewer = "viewer";
}

final class User
{
    public function __construct(
        public readonly string $name,
        public readonly Role $role = Role::Viewer,
    ) {}

    public function label(): string
    {
        return "{$this->name} ({$this->role->value})";
    }
}

$u = new User("Ann", Role::Admin);
echo $u->label(), "\n";               // Ann (admin)
echo Role::from("viewer")->name, "\n"; // Viewer

建構子提升(PHP 8.0)讓你直接在建構子簽章中宣告並賦值屬性。readonly 屬性(8.1)只能設定一次,而具值列舉(backed enum,8.1)可將各個 case 對應到字串或整數。也提供介面、抽象類別與 trait。

錯誤處理

現代 PHP 對大多數錯誤都會拋出例外。對可預期的失敗請捕捉 Exception 的子類別;Throwable 還涵蓋 TypeError 這類引擎層級的錯誤。

<?php
function parseAge(string $text): int
{
    if (!ctype_digit($text)) {
        throw new InvalidArgumentException("invalid age: $text");
    }
    return (int) $text;
}

try {
    echo parseAge("41"), "\n";   // 41
    echo parseAge("abc"), "\n";
} catch (InvalidArgumentException $e) {
    echo $e->getMessage(), "\n"; // invalid age: abc
} finally {
    echo "done\n";
}

完整的小程式:JSON API 端點

將它存成 api.php,執行 php -S localhost:8000,並開啟 http://localhost:8000/api.php?name=Ann。它會讀取一個查詢參數、驗證後回傳 JSON。

<?php
declare(strict_types=1);

header("Content-Type: application/json; charset=utf-8");

$name = trim($_GET["name"] ?? "");
if ($name === "" || mb_strlen($name) > 50) {
    http_response_code(400);
    echo json_encode(["error" => "name must be 1 to 50 characters"]);
    exit;
}

$response = [
    "message" => "Hello, $name!",
    "length" => mb_strlen($name),
    "time" => date(DATE_ATOM),
];
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

$_GET、$_POST 和 $_COOKIE 存放請求資料。請把其中的每個值都視為不可信。

初學者常見錯誤

  • 使用會轉換型別的 == 比較;請改用 === 和 !==。
  • 忘了變數名稱前的 $,或陳述式結尾的分號。
  • 使用 md5 或 sha1 儲存密碼。請使用 password_hash 與 password_verify。
  • 對 UTF-8 文字使用 strlen;它計算的是位元組數。要計算字元數請用 mb_strlen。
  • 執行舊版 PHP。請使用仍受支援的 PHP 8 版本,才能取得安全性修補與現代功能。

接下來學什麼

php.net 上的官方 PHP Manual 記載了每個函式,並附有語言參考與使用者備註。學習套件管理工具 Composer 與 PSR 程式碼風格標準,然後嘗試框架:應用程式可選 Laravel 或 Symfony,小型 API 可選 Slim。PHPUnit 是標準的測試工具。

常見問題

現在還值得學 PHP 嗎?

值得。網路上有很大一部分由它驅動,包括 WordPress 網站,而搭配 Laravel 或 Symfony 的現代 PHP 8 是開發網頁應用程式的高效率方式。維護與開發 PHP 系統的工作機會相當常見。

PHP 是前端還是後端語言?

後端。PHP 在伺服器上執行,並將完成的 HTML、JSON 或檔案傳送給瀏覽器,瀏覽器看不到 PHP 程式碼。

echo 和 print 有什麼差別?

兩者都輸出文字。echo 可以接受以逗號分隔的多個引數,且不回傳任何值;print 只接受一個引數,並回傳 1。實務上大多數程式碼都使用 echo。

declare(strict_types=1) 有什麼作用?

它讓該檔案發出的函式呼叫採用嚴格的純量型別宣告,所以把字串 "5" 傳給 int 參數時會拋出 TypeError,而不是自動轉換。

全部編碼教學