前言

PHP(Hypertext Preprocessor)是 Web 开发领域最成熟的语言之一。全球超过 75% 的网站使用 PHP,包括 WordPress、Facebook(早期)、Wikipedia。PHP 以部署简单、生态成熟、开发速度快著称。

本文将从零开始,带你系统掌握 PHP 的核心基础。

为什么选择 PHP?

优势 说明
🚀 即写即用 无需编译,保存即生效
🌐 为 Web 而生 天然支持 HTML 混写,处理表单、Cookie、Session 极方便
📦 生态成熟 Composer + Packagist 海量类库
💰 成本低 几乎所有虚拟主机都支持,云服务器部署简单
🎯 框架丰富 Laravel、Symfony、ThinkPHP 等

一、环境搭建

1.1 安装 PHP

Windows:下载 XAMPPPHPStudy

Linux

1
sudo apt install php php-cli php-fpm php-mysql php-curl php-mbstring

macOS

1
brew install php

1.2 验证安装

1
2
php --version
# PHP 8.3.0 (cli) (built: Nov 24 2024 ...

1.3 运行 PHP 代码

1
2
3
4
5
# 命令行运行
php hello.php

# 启动内置 Web 服务器(开发用)
php -S localhost:8000

二、第一个 PHP 程序

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>第一个 PHP 程序</title>
</head>
<body>
<h1><?php echo "Hello, 七月小站!"; ?></h1>
<p>现在时间是: <?php echo date("Y-m-d H:i:s"); ?></p>
</body>
</html>

💡 PHP 文件可以混合 HTML 和 PHP 代码。<?php ... ?> 标签内的代码在服务端执行,生成 HTML 后返回浏览器。


三、变量与数据类型

3.1 变量

PHP 变量以 $ 开头,松类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
// 变量声明
$name = "July";
$age = 25;
$height = 1.75;
$isActive = true;

// 可变变量(变量名存储在另一个变量中)
$varName = "age";
echo $$varName; // 25

// 引用赋值
$a = 10;
$b = &$a;
$b = 20;
echo $a; // 20

// 变量打印
echo $name;
var_dump($age); // int(25) — 带类型信息
print_r($name); // 直接显示值

echo "姓名: {$name}, 年龄: {$age}"; // 双引号解析变量
echo '姓名: ' . $name; // 单引号不解析,用 . 拼接
?>

3.2 数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 标量类型
$int = 42; // 整数
$float = 3.14; // 浮点数
$string = "Hello"; // 字符串
$bool = true; // 布尔值(true/false)

// 复合类型
$array = [1, 2, 3]; // 数组
$object = new stdClass(); // 对象

// 特殊类型
$null = null; // NULL
// resource — 外部资源(文件、数据库连接等)

// 类型检查和转换
echo gettype($int); // "integer"
echo is_int($int) ? "是整数" : "不是整数";
$strNum = (string) $int; // 强制转换
$intNum = (int) "123"; // 123

3.3 字符串操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$str = "Hello, PHP!";

// 常用函数
echo strlen($str); // 长度: 11
echo strpos($str, "PHP"); // 查找位置: 7
echo str_replace("PHP", "World", $str); // 替换
echo strtoupper($str); // 转大写
echo strtolower($str); // 转小写
echo substr($str, 0, 5); // 子串: "Hello"
echo trim(" hello "); // 去空格
echo str_contains($str, "PHP"); // 是否包含 (PHP 8.0+)
echo str_starts_with($str, "Hel"); // 前缀检查
echo str_ends_with($str, "!"); // 后缀检查

// 分割与连接
$parts = explode(", ", $str); // ["Hello", "PHP!"]
$joined = implode(" - ", $parts); // "Hello - PHP!"

四、数组(PHP 的核心数据结构)⭐

4.1 索引数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 创建
$fruits = ["苹果", "香蕉", "橘子"];
$fruits = array("苹果", "香蕉", "橘子"); // 旧式写法
$nums = range(1, 5); // [1, 2, 3, 4, 5]

// 访问
echo $fruits[0]; // 苹果

// 增删
$fruits[] = "草莓"; // 自动追加到末尾
array_push($fruits, "葡萄"); // 追加
array_unshift($fruits, "西瓜"); // 开头插入
$last = array_pop($fruits); // 弹出最后一个
$first = array_shift($fruits); // 弹出第一个
unset($fruits[1]); // 删除指定索引

// 遍历
foreach ($fruits as $fruit) {
echo $fruit . " ";
}

foreach ($fruits as $index => $fruit) {
echo "{$index}: {$fruit}\n";
}

4.2 关联数组(类似字典/Map)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$person = [
"name" => "July",
"age" => 25,
"city" => "深圳",
"hobbies" => ["编程", "阅读", "摄影"]
];

// 访问
echo $person["name"]; // July
echo $person["hobbies"][0]; // 编程

// 增改删
$person["email"] = "july@example.com"; // 增/改
unset($person["city"]); // 删

// 检查 key 是否存在
if (array_key_exists("age", $person)) {
echo "age 已设置";
}
// 或 PHP 8.4+
if (isset($person["age"])) {
echo "age 已设置";
}

// 遍历
foreach ($person as $key => $value) {
echo "{$key}: {$value}\n";
}

4.3 常用数组函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$nums = [3, 1, 4, 1, 5, 9, 2, 6];

// 统计
echo count($nums); // 8(元素个数)
echo array_sum($nums); // 31(求和)
echo max($nums); // 9
echo min($nums); // 1

// 排序
sort($nums); // 升序排序(修改原数组)
rsort($nums); // 降序
asort($person); // 按值排序(保持键)
ksort($person); // 按键排序

// 过滤和映射
$evens = array_filter($nums, function($n) {
return $n % 2 == 0;
});

$doubled = array_map(function($n) {
return $n * 2;
}, $nums);

// 合并
$a = ["a" => 1, "b" => 2];
$b = ["b" => 3, "c" => 4];
$merged = array_merge($a, $b); // 后面覆盖前面
// ["a" => 1, "b" => 3, "c" => 4]

$spread = [...$a, ...$b]; // PHP 8.1+, 数组展开

// 去重
$unique = array_unique([1, 2, 2, 3, 3, 3]);

// 反转
$reversed = array_reverse($nums);

// 是否有交集
$hasCommon = !empty(array_intersect([1, 2], [2, 3])); // true

五、流程控制

5.1 if / else

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$score = 85;

if ($score >= 90) {
$grade = "A";
} elseif ($score >= 80) {
$grade = "B";
} elseif ($score >= 60) {
$grade = "C";
} else {
$grade = "D";
}

echo "等级: {$grade}";

// 三元运算符
$status = ($age >= 18) ? "成年" : "未成年";

// null 合并运算符
$name = $_GET["name"] ?? "访客"; // 如果 $_GET["name"] 为 null,使用默认值

// null 合并赋值 (PHP 7.4+)
$config ??= "default";

5.2 match 表达式(PHP 8.0+,替代 switch)

1
2
3
4
5
6
7
8
9
10
11
12
// PHP 8.0+ match 表达式(严格比较,有返回值)
$day = 3;
$dayName = match ($day) {
1 => "星期一",
2 => "星期二",
3 => "星期三",
4 => "星期四",
5 => "星期五",
6, 7 => "周末", // 多个值匹配
default => "无效"
};
echo $dayName; // 星期三

5.3 传统 switch

1
2
3
4
5
6
7
8
9
10
switch ($day) {
case 1:
echo "星期一";
break;
case 2:
echo "星期二";
break;
default:
echo "其他";
}

5.4 循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// for 循环
for ($i = 0; $i < 5; $i++) {
echo $i . " ";
}
// 0 1 2 3 4

// while 循环
$count = 0;
while ($count < 5) {
echo $count . " ";
$count++;
}

// do-while(至少执行一次)
do {
echo "执行";
} while (false);

// foreach(遍历数组最常用)
$fruits = ["苹果", "香蕉", "橘子"];
foreach ($fruits as $fruit) {
echo $fruit . "\n";
}

六、函数

6.1 基本函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 定义函数
function greet($name) {
return "你好,{$name}!";
}

function add($a, $b = 10) { // 默认参数
return $a + $b;
}

// 类型声明(PHP 7.0+)
function multiply(int $a, int $b): int {
return $a * $b;
}

// 可空类型(?)和联合类型(|)
function getUser(?int $id): ?array {
if ($id === null) return null;
return ["id" => $id, "name" => "July"];
}

// 命名参数(PHP 8.0+)
echo add(b: 5, a: 3); // 可以按名称传参,不按顺序

// 可变参数 ...(splat 操作符)
function sumAll(...$nums) {
return array_sum($nums);
}
echo sumAll(1, 2, 3, 4, 5); // 15

6.2 匿名函数(闭包)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 匿名函数
$double = function($x) {
return $x * 2;
};
echo $double(5); // 10

// 使用外部变量
$multiplier = 3;
$triple = function($x) use ($multiplier) {
return $x * $multiplier;
};
echo $triple(5); // 15

// 箭头函数(PHP 7.4+,自动捕获外部变量)
$multiplier = 3;
$triple = fn($x) => $x * $multiplier;
echo $triple(5); // 15

// 配合数组函数
$nums = [1, 2, 3, 4, 5];
$doubled = array_map(fn($n) => $n * 2, $nums);

6.3 变量作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$globalVar = "全局变量";

function test() {
$localVar = "局部变量";

// 访问全局变量需要 global 关键字
global $globalVar;
echo $globalVar;

// 或使用 $GLOBALS 数组
echo $GLOBALS["globalVar"];
}

// 静态变量(函数调用间保持值)
function counter() {
static $count = 0;
$count++;
return $count;
}
echo counter(); // 1
echo counter(); // 2
echo counter(); // 3

七、面向对象编程(OOP)

7.1 类与对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class User
{
// 属性(PHP 8.1+ 支持 readonly)
public string $username;
public string $email;
private string $password;
protected int $age;

// 静态属性
public static int $count = 0;

// 常量
const ROLE_USER = "user";
const ROLE_ADMIN = "admin";

// 构造方法
public function __construct(
string $username,
string $email,
string $password,
int $age = 18
) {
$this->username = $username;
$this->email = $email;
$this->password = password_hash($password, PASSWORD_DEFAULT);
$this->age = $age;
self::$count++;
}

// Getter
public function getAge(): int
{
return $this->age;
}

// Setter(带验证)
public function setAge(int $age): void
{
if ($age < 0 || $age > 150) {
throw new InvalidArgumentException("无效的年龄");
}
$this->age = $age;
}

// 实例方法
public function greet(): string
{
return "你好,我是{$this->username}";
}

// 验证密码
public function verifyPassword(string $password): bool
{
return password_verify($password, $this->password);
}

// 静态方法
public static function getCount(): int
{
return self::$count;
}

// 析构方法
public function __destruct()
{
// 对象销毁时调用
}

// 字符串表示
public function __toString(): string
{
return "User({$this->username})";
}
}

// 使用
$user1 = new User("July", "july@example.com", "secret123", 25);
$user2 = new User("zhangsan", "zhangsan@example.com", "pass456");

echo $user1->greet(); // 你好,我是July
echo User::$count; // 2
echo User::ROLE_ADMIN; // admin
echo $user1; // User(July)

7.2 继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class Animal
{
public function __construct(
protected string $name
) {}

public function speak(): string
{
return "...";
}

public function getName(): string
{
return $this->name;
}
}

class Dog extends Animal
{
public function __construct(
string $name,
private string $breed
) {
parent::__construct($name);
}

// 重写方法
public function speak(): string
{
return "汪汪汪!";
}

public function getBreed(): string
{
return $this->breed;
}
}

class Cat extends Animal
{
public function speak(): string
{
return "喵喵喵!";
}
}

// 多态
$animals = [
new Dog("旺财", "金毛"),
new Cat("小花"),
];

foreach ($animals as $animal) {
echo "{$animal->getName()} 说: {$animal->speak()}\n";
}

7.3 接口与抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 接口
interface LoggerInterface
{
public function log(string $message): void;
}

interface FormatterInterface
{
public function format(string $message): string;
}

// 实现多个接口
class FileLogger implements LoggerInterface, FormatterInterface
{
public function __construct(private string $filepath) {}

public function log(string $message): void
{
$formatted = $this->format($message);
file_put_contents($this->filepath, $formatted . "\n", FILE_APPEND);
}

public function format(string $message): string
{
return sprintf("[%s] %s", date("Y-m-d H:i:s"), $message);
}
}

// 使用接口类型提示
function runApp(LoggerInterface $logger): void {
// 任意实现了 LoggerInterface 的对象都可以传入
$logger->log("应用启动");
}

// Trait(代码复用,类似混入/Mixin)
trait Timestampable
{
private \DateTime $createdAt;
private \DateTime $updatedAt;

public function initTimestamps(): void
{
$this->createdAt = new \DateTime();
$this->updatedAt = new \DateTime();
}

public function getCreatedAt(): \DateTime
{
return $this->createdAt;
}
}

class Article
{
use Timestampable;

public function __construct(string $title)
{
$this->initTimestamps();
}
}

八、表单处理

PHP 处理表单是最常见的 Web 开发场景。

8.1 HTML 表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- form.html -->
<form action="submit.php" method="POST" enctype="multipart/form-data">
<label>姓名:<input type="text" name="username" required></label><br>
<label>邮箱:<input type="email" name="email"></label><br>
<label>年龄:<input type="number" name="age" min="1" max="150"></label><br>
<label>性别:
<input type="radio" name="gender" value="male">
<input type="radio" name="gender" value="female">
</label><br>
<label>爱好:
<input type="checkbox" name="hobbies[]" value="coding"> 编程
<input type="checkbox" name="hobbies[]" value="reading"> 阅读
<input type="checkbox" name="hobbies[]" value="sports"> 运动
</label><br>
<label>个人简介:<textarea name="bio"></textarea></label><br>
<label>头像:<input type="file" name="avatar"></label><br>
<button type="submit">提交</button>
</form>

8.2 处理表单数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?php
// submit.php — 处理 POST 请求

// 检查请求方法
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
die("只接受 POST 请求");
}

// 获取并安全处理表单数据
$username = trim($_POST["username"] ?? "");
$email = filter_input(INPUT_POST, "email", FILTER_VALIDATE_EMAIL);
$age = (int) ($_POST["age"] ?? 0);
$gender = $_POST["gender"] ?? "未指定";
$hobbies = $_POST["hobbies"] ?? [];
$bio = strip_tags($_POST["bio"] ?? ""); // 去除 HTML 标签防止 XSS

// 验证
$errors = [];

if (empty($username)) {
$errors[] = "姓名不能为空";
}
if (!$email) {
$errors[] = "邮箱格式不正确";
}
if ($age < 1 || $age > 150) {
$errors[] = "年龄不合理";
}

// 文件上传处理
if (isset($_FILES["avatar"]) && $_FILES["avatar"]["error"] === UPLOAD_ERR_OK) {
$allowedTypes = ["image/jpeg", "image/png", "image/gif"];
$maxSize = 2 * 1024 * 1024; // 2MB

$file = $_FILES["avatar"];

if (!in_array($file["type"], $allowedTypes)) {
$errors[] = "只允许 JPG/PNG/GIF 格式";
}
if ($file["size"] > $maxSize) {
$errors[] = "文件不能超过 2MB";
}

if (empty($errors)) {
$ext = pathinfo($file["name"], PATHINFO_EXTENSION);
$newName = uniqid("avatar_") . "." . $ext;
$uploadPath = __DIR__ . "/uploads/" . $newName;

if (!is_dir(__DIR__ . "/uploads")) {
mkdir(__DIR__ . "/uploads", 0755, true);
}
move_uploaded_file($file["tmp_name"], $uploadPath);
echo "头像上传成功: {$newName}<br>";
}
}

// 显示错误
if (!empty($errors)) {
foreach ($errors as $error) {
echo "<p style='color:red'>❌ {$error}</p>";
}
exit;
}

// 输出结果(实际开发中应存入数据库)
echo "<h2>提交成功!</h2>";
echo "<p>姓名: " . htmlspecialchars($username) . "</p>";
echo "<p>邮箱: " . htmlspecialchars($email) . "</p>";
echo "<p>年龄: {$age}</p>";
echo "<p>性别: {$gender}</p>";
echo "<p>爱好: " . implode(", ", $hobbies) . "</p>";
?>

九、数据库操作(MySQL + PDO)

PDO(PHP Data Objects)是 PHP 访问数据库的统一接口,安全、支持预处理语句

9.1 数据库连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
// database.php — 数据库连接
function getDB(): PDO {
static $pdo = null;

if ($pdo === null) {
$host = "localhost";
$dbname = "my_blog";
$username = "root";
$password = "your_password";
$charset = "utf8mb4";

$dsn = "mysql:host={$host};dbname={$dbname};charset={$charset}";

$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 异常模式
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 默认关联数组
PDO::ATTR_EMULATE_PREPARES => false, // 原生预处理
];

$pdo = new PDO($dsn, $username, $password, $options);
}

return $pdo;
}
?>

9.2 CRUD 操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<?php
require_once "database.php";

$db = getDB();

// ===== CREATE — 插入数据 =====
$stmt = $db->prepare("INSERT INTO users (username, email, password) VALUES (?, ?, ?)");
$stmt->execute(["July", "july@example.com", password_hash("secret123", PASSWORD_DEFAULT)]);
$newId = $db->lastInsertId();
echo "新增用户 ID: {$newId}<br>";

// 命名占位符方式(可读性更好)
$stmt = $db->prepare("INSERT INTO users (username, email, password) VALUES (:name, :email, :pass)");
$stmt->execute([
":name" => "zhangsan",
":email" => "zhangsan@example.com",
":pass" => password_hash("pass456", PASSWORD_DEFAULT),
]);

// ===== READ — 查询数据 =====
// 查询所有
$stmt = $db->query("SELECT id, username, email, created_at FROM users ORDER BY id DESC");
$users = $stmt->fetchAll();
foreach ($users as $user) {
echo "{$user["id"]}: {$user["username"]} ({$user["email"]})<br>";
}

// 条件查询
$stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute(["July"]);
$user = $stmt->fetch(); // 获取单条
if ($user) {
echo "找到用户: {$user["username"]}<br>";
}

// 分页查询
$page = (int) ($_GET["page"] ?? 1);
$perPage = 10;
$offset = ($page - 1) * $perPage;

$stmt = $db->prepare("SELECT * FROM users ORDER BY id DESC LIMIT ? OFFSET ?");
$stmt->execute([$perPage, $offset]);
$users = $stmt->fetchAll();

// 统计总数
$total = $db->query("SELECT COUNT(*) FROM users")->fetchColumn();
$totalPages = ceil($total / $perPage);

// ===== UPDATE — 更新数据 =====
$stmt = $db->prepare("UPDATE users SET email = ?, updated_at = NOW() WHERE id = ?");
$stmt->execute(["new_email@example.com", $newId]);
echo "更新了 {$stmt->rowCount()} 行<br>";

// ===== DELETE — 删除数据 =====
$stmt = $db->prepare("DELETE FROM users WHERE id = ?");
$stmt->execute([$newId]);
echo "删除了 {$stmt->rowCount()} 行<br>";
?>

9.3 安全查询要点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ❌ 危险:直接拼接 SQL(SQL 注入风险!)
$username = $_GET["username"];
$db->query("SELECT * FROM users WHERE username = '{$username}'"); // 绝对不要这样做!

// ✅ 安全:使用预处理语句
$stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$_GET["username"]]);

// ✅ IN 子句的动态占位符
$ids = [1, 2, 3, 4, 5];
$placeholders = implode(",", array_fill(0, count($ids), "?"));
$stmt = $db->prepare("SELECT * FROM users WHERE id IN ({$placeholders})");
$stmt->execute($ids);

// ✅ 动态搜索(LIKE)
$keyword = $_GET["q"] ?? "";
$stmt = $db->prepare("SELECT * FROM posts WHERE title LIKE ?");
$stmt->execute(["%{$keyword}%"]);

9.4 简单的事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
try {
$db->beginTransaction();

// 插入文章
$stmt = $db->prepare("INSERT INTO posts (title, content, user_id) VALUES (?, ?, ?)");
$stmt->execute(["文章标题", "文章内容", 1]);
$postId = $db->lastInsertId();

// 插入标签关联
$stmt = $db->prepare("INSERT INTO post_tags (post_id, tag_id) VALUES (?, ?)");
$stmt->execute([$postId, 5]);
$stmt->execute([$postId, 8]);

$db->commit();
echo "文章发布成功!";
} catch (Exception $e) {
$db->rollBack();
echo "发布失败: " . $e->getMessage();
}

十、Cookie 与 Session

10.1 Cookie(客户端存储)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 设置 Cookie(在输出任何 HTML 之前!)
setcookie("username", "July", time() + 3600 * 24 * 30, "/"); // 30 天有效
setcookie("theme", "dark", [
"expires" => time() + 3600 * 24 * 30,
"path" => "/",
"secure" => true, // 仅 HTTPS
"httponly" => true, // JS 无法访问
"samesite" => "Lax",
]);

// 读取 Cookie
$username = $_COOKIE["username"] ?? null;

// 删除 Cookie
setcookie("username", "", time() - 3600, "/");

10.2 Session(服务端存储)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 启动会话(必须在输出 HTML 之前调用)
session_start();

// 存储数据
$_SESSION["user_id"] = 42;
$_SESSION["username"] = "July";
$_SESSION["logged_in"] = true;
$_SESSION["cart"] = [
["id" => 1, "name" => "商品A", "qty" => 2],
["id" => 2, "name" => "商品B", "qty" => 1],
];

// 读取数据
$userName = $_SESSION["username"] ?? "访客";

// 删除单个键
unset($_SESSION["cart"]);

// 销毁整个 Session
session_destroy();

// 完整登录检查示例
session_start();
function isLoggedIn(): bool {
return isset($_SESSION["user_id"]);
}

function requireLogin(): void {
if (!isLoggedIn()) {
header("Location: /login.php");
exit;
}
}

十一、文件操作与常用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 读取文件
$content = file_get_contents("data.txt");
$lines = file("data.txt"); // 读取为数组,每行一个元素

// 写入文件
file_put_contents("output.txt", "Hello World\n");
file_put_contents("output.txt", "追加内容\n", FILE_APPEND);

// 检查文件
if (file_exists("data.txt")) {
echo "文件大小: " . filesize("data.txt") . " 字节";
echo "修改时间: " . date("Y-m-d", filemtime("data.txt"));
}

// 目录操作
$files = scandir("/path/to/dir"); // 列出目录
is_dir("/path");
mkdir("/path/to/newdir", 0755, true); // 递归创建

// 常用字符串函数
htmlspecialchars("<script>alert('xss')</script>"); // 转义 HTML → XSS 防护
strip_tags("<p>Hello</p><script>evil()</script>"); // 去除 HTML/PHP 标签
urlencode("搜索 关键词"); // URL 编码
json_encode(["name" => "July"], JSON_UNESCAPED_UNICODE); // JSON 编码
json_decode('{"name":"July"}', true); // JSON 解码 → 关联数组

// 日期时间
echo date("Y-m-d H:i:s"); // 当前时间
echo date("Y-m-d H:i:s", strtotime("+1 week"));
echo time(); // Unix 时间戳

十二、实战:简易博客 API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?php
// api.php — 简易博客 API
header("Content-Type: application/json; charset=utf-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");

if ($_SERVER["REQUEST_METHOD"] === "OPTIONS") {
http_response_code(200);
exit;
}

require_once "database.php";
$db = getDB();

$method = $_SERVER["REQUEST_METHOD"];
$path = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);

// 路由解析
if (preg_match('#^/api/articles$#', $path)) {
switch ($method) {
case "GET":
$stmt = $db->query("SELECT * FROM posts WHERE status = 1 ORDER BY id DESC LIMIT 20");
$articles = $stmt->fetchAll();
echo json_encode(["code" => 200, "data" => $articles], JSON_UNESCAPED_UNICODE);
break;

case "POST":
$input = json_decode(file_get_contents("php://input"), true);

if (empty($input["title"]) || empty($input["content"])) {
http_response_code(400);
echo json_encode(["code" => 400, "msg" => "标题和内容不能为空"]);
exit;
}

$stmt = $db->prepare("INSERT INTO posts (title, content, user_id) VALUES (?, ?, ?)");
$stmt->execute([$input["title"], $input["content"], $input["user_id"] ?? 1]);

echo json_encode([
"code" => 201,
"msg" => "创建成功",
"id" => $db->lastInsertId()
], JSON_UNESCAPED_UNICODE);
break;

default:
http_response_code(405);
echo json_encode(["code" => 405, "msg" => "方法不允许"]);
}
}
elseif (preg_match('#^/api/articles/(\d+)$#', $path, $matches)) {
$id = (int) $matches[1];

switch ($method) {
case "GET":
$stmt = $db->prepare("SELECT * FROM posts WHERE id = ?");
$stmt->execute([$id]);
$article = $stmt->fetch();

if (!$article) {
http_response_code(404);
echo json_encode(["code" => 404, "msg" => "文章不存在"]);
exit;
}
echo json_encode(["code" => 200, "data" => $article], JSON_UNESCAPED_UNICODE);
break;

case "PUT":
$input = json_decode(file_get_contents("php://input"), true);
$stmt = $db->prepare("UPDATE posts SET title = ?, content = ?, updated_at = NOW() WHERE id = ?");
$stmt->execute([$input["title"], $input["content"], $id]);
echo json_encode(["code" => 200, "msg" => "更新成功"]);
break;

case "DELETE":
$stmt = $db->prepare("DELETE FROM posts WHERE id = ?");
$stmt->execute([$id]);
echo json_encode(["code" => 200, "msg" => "删除成功"]);
break;

default:
http_response_code(405);
echo json_encode(["code" => 405, "msg" => "方法不允许"]);
}
}
else {
http_response_code(404);
echo json_encode(["code" => 404, "msg" => "路由不存在"]);
}
?>

启动并测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
php -S localhost:8000

# 获取文章列表
curl http://localhost:8000/api/articles

# 创建文章
curl -X POST http://localhost:8000/api/articles \
-H "Content-Type: application/json" \
-d '{"title":"PHP基础教程","content":"这是内容","user_id":1}'

# 获取单篇文章
curl http://localhost:8000/api/articles/1

# 更新文章
curl -X PUT http://localhost:8000/api/articles/1 \
-H "Content-Type: application/json" \
-d '{"title":"PHP进阶教程","content":"更新的内容"}'

# 删除文章
curl -X DELETE http://localhost:8000/api/articles/1

十三、Composer 与第三方库

1
2
3
4
5
6
7
8
9
10
# 安装 Composer(依赖管理工具)
# Linux / macOS
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

# 初始化项目
composer init
composer require phpmailer/phpmailer
composer require monolog/monolog
composer install # 从 composer.lock 安装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
require_once "vendor/autoload.php"; // 自动加载

// 使用 Monolog 记录日志
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$log = new Logger("myapp");
$log->pushHandler(new StreamHandler("app.log", Logger::WARNING));
$log->warning("这是一个警告");
$log->error("发生错误", ["user_id" => 42]);

// 使用 PHPMailer 发送邮件
use PHPMailer\PHPMailer\PHPMailer;

$mail = new PHPMailer(true);
$mail->setFrom("from@example.com", "七月小站");
$mail->addAddress("to@example.com");
$mail->Subject = "测试邮件";
$mail->Body = "<h1>Hello</h1><p>这是一封测试邮件</p>";
$mail->isHTML(true);
$mail->send();
?>

常用 PHP 命令速查

命令 说明
php -v 查看 PHP 版本
php file.php 运行 PHP 文件
php -S localhost:8000 启动开发服务器
php -m 列出已安装的扩展模块
php -i 显示 PHP 配置信息(phpinfo)
php -r "echo 'hello';" 执行一行 PHP 代码
composer install 安装依赖
composer require pkg 添加新的依赖包

安全最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 1. XSS 防护:输出时转义
echo htmlspecialchars($userInput, ENT_QUOTES, "UTF-8");

// 2. SQL 注入防护:永远使用预处理语句
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);

// 3. CSRF 防护:使用 Token
session_start();
if ($_SERVER["REQUEST_METHOD"] === "POST") {
if ($_POST["csrf_token"] !== $_SESSION["csrf_token"]) {
die("CSRF 验证失败");
}
}
$_SESSION["csrf_token"] = bin2hex(random_bytes(32));
// 在表单中: <input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">

// 4. 密码哈希
$hashed = password_hash($password, PASSWORD_DEFAULT);
// 验证:
password_verify($inputPassword, $hashed);

// 5. 文件上传验证
$allowed = ["image/jpeg", "image/png"];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES["file"]["tmp_name"]);
if (!in_array($mime, $allowed)) { die("不允许的文件类型"); }

进一步学习

  1. Web 框架:Laravel(全栈)、Symfony(企业级)、ThinkPHP(国产)
  2. CMS:WordPress 主题/插件开发
  3. 模板引擎:Blade(Laravel)、Twig(Symfony)
  4. 测试:PHPUnit
  5. 设计模式:工厂模式、单例模式、依赖注入等在 PHP 中的实践

结语

PHP 作为互联网的”老黄牛”,支撑着全球 75% 以上的网站。它上手简单、部署方便、生态丰富,非常适合快速开发 Web 应用。

本文涵盖了 PHP 开发中最核心的知识点。配合现代 PHP 8.x 的新特性(命名参数、match 表达式、类型系统、JIT 编译器等),PHP 的开发体验已经今非昔比。

别听别人说”PHP 是最好的语言”或”PHP 已死”——自己去写个小项目感受一下吧!🐘