本章目标

  • 掌握条件语句的使用
  • 学会各种循环结构
  • 了解跳转语句的应用
  • 掌握流程控制的最佳实践
  • 学会处理复杂的逻辑结构

3.1 条件语句

3.1.1 if语句

基本语法

<?php
$score = 85;

// 基本if语句
if ($score >= 60) {
    echo "及格了!";
}

// if-else语句
if ($score >= 90) {
    echo "优秀";
} else {
    echo "良好";
}

// if-elseif-else语句
if ($score >= 90) {
    echo "优秀";
} elseif ($score >= 80) {
    echo "良好";
} elseif ($score >= 70) {
    echo "中等";
} elseif ($score >= 60) {
    echo "及格";
} else {
    echo "不及格";
}
?>

复杂条件判断

<?php
$age = 25;
$hasLicense = true;
$hasInsurance = true;

// 多条件判断
if ($age >= 18 && $hasLicense && $hasInsurance) {
    echo "可以开车";
} else {
    echo "不能开车";
    
    if ($age < 18) {
        echo "原因:年龄不够";
    } elseif (!$hasLicense) {
        echo "原因:没有驾照";
    } elseif (!$hasInsurance) {
        echo "原因:没有保险";
    }
}

// 嵌套if语句
if ($age >= 18) {
    if ($hasLicense) {
        if ($hasInsurance) {
            echo "可以开车";
        } else {
            echo "需要购买保险";
        }
    } else {
        echo "需要考取驾照";
    }
} else {
    echo "年龄不够";
}
?>

三元运算符

<?php
$age = 20;

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

// 嵌套三元运算符(不推荐)
$level = ($score >= 90) ? "优秀" : (($score >= 80) ? "良好" : "一般");

// NULL合并运算符(PHP 7+)
$username = $_GET['user'] ?? 'guest';
$config = $userConfig ?? $defaultConfig ?? [];

// NULL合并赋值运算符(PHP 7.4+)
$config['debug'] ??= false;
$config['timeout'] ??= 30;
?>

3.1.2 switch语句

基本用法

<?php
$day = date('w'); // 0-6,0表示周日

switch ($day) {
    case 0:
        echo "今天是周日";
        break;
    case 1:
        echo "今天是周一";
        break;
    case 2:
        echo "今天是周二";
        break;
    case 3:
        echo "今天是周三";
        break;
    case 4:
        echo "今天是周四";
        break;
    case 5:
        echo "今天是周五";
        break;
    case 6:
        echo "今天是周六";
        break;
    default:
        echo "未知的日期";
        break;
}
?>

多个case共享代码

<?php
$month = date('n'); // 1-12

switch ($month) {
    case 12:
    case 1:
    case 2:
        echo "冬季";
        break;
    case 3:
    case 4:
    case 5:
        echo "春季";
        break;
    case 6:
    case 7:
    case 8:
        echo "夏季";
        break;
    case 9:
    case 10:
    case 11:
        echo "秋季";
        break;
    default:
        echo "无效的月份";
        break;
}
?>

switch的穿透特性

<?php
$grade = 'B';
$points = 0;

switch ($grade) {
    case 'A':
        $points += 10; // A级额外加10分
    case 'B':
        $points += 20; // B级加20分
    case 'C':
        $points += 30; // C级加30分
        break;
    case 'D':
        $points = 10;
        break;
    default:
        $points = 0;
}

echo "得分:$points"; // B级得分:50(20+30)
?>

switch表达式(PHP 8+)

<?php
$day = date('w');

// 传统switch
switch ($day) {
    case 0:
    case 6:
        $dayType = '周末';
        break;
    default:
        $dayType = '工作日';
        break;
}

// PHP 8+ match表达式
$dayType = match($day) {
    0, 6 => '周末',
    default => '工作日'
};

// 更复杂的match表达式
$httpCode = 404;
$message = match($httpCode) {
    200 => '成功',
    404 => '页面未找到',
    500 => '服务器错误',
    400, 401, 403 => '客户端错误',
    default => '未知错误'
};
?>

3.2 循环语句

3.2.1 for循环

基本语法

<?php
// 基本for循环
for ($i = 1; $i <= 10; $i++) {
    echo "数字:$i\n";
}

// 倒序循环
for ($i = 10; $i >= 1; $i--) {
    echo "倒数:$i\n";
}

// 步长为2的循环
for ($i = 0; $i <= 20; $i += 2) {
    echo "偶数:$i\n";
}

// 多变量循环
for ($i = 0, $j = 10; $i < $j; $i++, $j--) {
    echo "i=$i, j=$j\n";
}
?>

嵌套for循环

<?php
// 打印乘法表
echo "<table border='1'>";
for ($i = 1; $i <= 9; $i++) {
    echo "<tr>";
    for ($j = 1; $j <= $i; $j++) {
        $result = $i * $j;
        echo "<td>$j × $i = $result</td>";
    }
    echo "</tr>";
}
echo "</table>";

// 打印星号图案
for ($i = 1; $i <= 5; $i++) {
    for ($j = 1; $j <= $i; $j++) {
        echo "*";
    }
    echo "\n";
}
/*
输出:
*
**
***
****
*****
*/
?>

3.2.2 while循环

基本用法

<?php
// 基本while循环
$i = 1;
while ($i <= 5) {
    echo "循环第 $i 次\n";
    $i++;
}

// 读取文件内容
$file = fopen('data.txt', 'r');
while (!feof($file)) {
    $line = fgets($file);
    echo $line;
}
fclose($file);

// 用户输入验证
$password = '';
while (strlen($password) < 6) {
    echo "请输入密码(至少6位):";
    $password = trim(fgets(STDIN));
    if (strlen($password) < 6) {
        echo "密码太短,请重新输入!\n";
    }
}
echo "密码设置成功!";
?>

无限循环和退出条件

<?php
// 无限循环(需要内部break)
while (true) {
    echo "请输入命令(quit退出):";
    $input = trim(fgets(STDIN));
    
    if ($input === 'quit') {
        echo "再见!";
        break;
    }
    
    echo "您输入了:$input\n";
}

// 条件复杂的while循环
$attempts = 0;
$maxAttempts = 3;
$success = false;

while ($attempts < $maxAttempts && !$success) {
    echo "尝试连接数据库...";
    $success = connectToDatabase(); // 假设的函数
    
    if (!$success) {
        $attempts++;
        echo "连接失败,重试中... ($attempts/$maxAttempts)\n";
        sleep(1); // 等待1秒
    }
}

if ($success) {
    echo "连接成功!";
} else {
    echo "连接失败,已达到最大重试次数。";
}
?>

3.2.3 do-while循环

<?php
// 基本do-while循环
$i = 1;
do {
    echo "执行第 $i 次\n";
    $i++;
} while ($i <= 5);

// 至少执行一次的特性
$number = 10;
do {
    echo "数字:$number\n";
    $number++;
} while ($number < 5); // 条件为false,但仍会执行一次

// 菜单系统
do {
    echo "\n=== 主菜单 ===\n";
    echo "1. 查看用户\n";
    echo "2. 添加用户\n";
    echo "3. 删除用户\n";
    echo "0. 退出\n";
    echo "请选择:";
    
    $choice = trim(fgets(STDIN));
    
    switch ($choice) {
        case '1':
            echo "查看用户功能\n";
            break;
        case '2':
            echo "添加用户功能\n";
            break;
        case '3':
            echo "删除用户功能\n";
            break;
        case '0':
            echo "退出系统\n";
            break;
        default:
            echo "无效选择,请重新输入\n";
    }
} while ($choice !== '0');
?>

3.2.4 foreach循环

遍历数组

<?php
// 遍历索引数组
$fruits = ['苹果', '香蕉', '橙子', '葡萄'];

foreach ($fruits as $fruit) {
    echo "水果:$fruit\n";
}

// 遍历关联数组
$person = [
    'name' => '张三',
    'age' => 25,
    'city' => '北京',
    'email' => 'zhangsan@example.com'
];

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

// 遍历多维数组
$users = [
    ['name' => '张三', 'age' => 25],
    ['name' => '李四', 'age' => 30],
    ['name' => '王五', 'age' => 28]
];

foreach ($users as $index => $user) {
    echo "用户 $index:\n";
    foreach ($user as $key => $value) {
        echo "  $key: $value\n";
    }
}
?>

引用遍历

<?php
$numbers = [1, 2, 3, 4, 5];

// 通过引用修改数组元素
foreach ($numbers as &$number) {
    $number *= 2; // 每个元素乘以2
}
unset($number); // 销毁引用

print_r($numbers); // [2, 4, 6, 8, 10]

// 条件修改
$products = [
    ['name' => '商品A', 'price' => 100, 'discount' => false],
    ['name' => '商品B', 'price' => 200, 'discount' => false],
    ['name' => '商品C', 'price' => 150, 'discount' => false]
];

// 给价格超过150的商品打折
foreach ($products as &$product) {
    if ($product['price'] > 150) {
        $product['discount'] = true;
        $product['price'] *= 0.8; // 8折
    }
}
unset($product);

print_r($products);
?>

遍历对象

<?php
class User {
    public $name = '张三';
    public $age = 25;
    private $password = 'secret';
    protected $email = 'zhangsan@example.com';
    
    public function getInfo() {
        return "姓名:{$this->name},年龄:{$this->age}";
    }
}

$user = new User();

// 只能遍历公共属性
foreach ($user as $property => $value) {
    echo "$property: $value\n";
}
// 输出:
// name: 张三
// age: 25

// 在类内部可以遍历所有属性
class UserManager {
    public function showUserProperties(User $user) {
        foreach ($user as $property => $value) {
            echo "$property: $value\n";
        }
    }
}
?>

3.3 跳转语句

3.3.1 break语句

<?php
// 在循环中使用break
for ($i = 1; $i <= 10; $i++) {
    if ($i === 5) {
        break; // 跳出循环
    }
    echo "$i ";
}
// 输出:1 2 3 4

// 在嵌套循环中使用break
for ($i = 1; $i <= 3; $i++) {
    for ($j = 1; $j <= 3; $j++) {
        if ($i === 2 && $j === 2) {
            break; // 只跳出内层循环
        }
        echo "($i,$j) ";
    }
    echo "\n";
}
// 输出:
// (1,1) (1,2) (1,3)
// (2,1)
// (3,1) (3,2) (3,3)

// 使用break跳出多层循环
for ($i = 1; $i <= 3; $i++) {
    for ($j = 1; $j <= 3; $j++) {
        if ($i === 2 && $j === 2) {
            break 2; // 跳出两层循环
        }
        echo "($i,$j) ";
    }
    echo "\n";
}
// 输出:
// (1,1) (1,2) (1,3)
// (2,1)

// 在switch中使用break
$grade = 'B';
switch ($grade) {
    case 'A':
        echo "优秀";
        break;
    case 'B':
        echo "良好";
        break; // 防止穿透到下一个case
    case 'C':
        echo "及格";
        break;
    default:
        echo "不及格";
}
?>

3.3.2 continue语句

<?php
// 跳过偶数
for ($i = 1; $i <= 10; $i++) {
    if ($i % 2 === 0) {
        continue; // 跳过本次循环的剩余代码
    }
    echo "奇数:$i\n";
}

// 处理数组时跳过某些元素
$numbers = [1, 2, 3, 0, 5, 6, 0, 8, 9];
foreach ($numbers as $number) {
    if ($number === 0) {
        continue; // 跳过0
    }
    echo "处理数字:$number\n";
}

// 在嵌套循环中使用continue
for ($i = 1; $i <= 3; $i++) {
    for ($j = 1; $j <= 3; $j++) {
        if ($j === 2) {
            continue; // 跳过内层循环的当前迭代
        }
        echo "($i,$j) ";
    }
    echo "\n";
}
// 输出:
// (1,1) (1,3)
// (2,1) (2,3)
// (3,1) (3,3)

// 使用continue跳过多层循环
for ($i = 1; $i <= 3; $i++) {
    for ($j = 1; $j <= 3; $j++) {
        if ($i === 2) {
            continue 2; // 跳过外层循环的当前迭代
        }
        echo "($i,$j) ";
    }
    echo "\n";
}
// 输出:
// (1,1) (1,2) (1,3)
// (3,1) (3,2) (3,3)
?>

3.3.3 goto语句

<?php
// 基本goto用法(不推荐使用)
$i = 0;

start:
echo "i = $i\n";
$i++;

if ($i < 5) {
    goto start;
}

echo "循环结束\n";

// goto跳出嵌套循环(替代break的复杂用法)
for ($i = 1; $i <= 3; $i++) {
    for ($j = 1; $j <= 3; $j++) {
        if ($i === 2 && $j === 2) {
            goto end; // 跳到end标签
        }
        echo "($i,$j) ";
    }
}

end:
echo "\n跳出所有循环\n";

// 错误处理中的goto(不推荐)
function processData($data) {
    if (empty($data)) {
        goto error;
    }
    
    if (!is_array($data)) {
        goto error;
    }
    
    // 处理数据
    return $data;
    
    error:
    throw new Exception('数据无效');
}
?>

3.3.4 return语句

<?php
// 函数中的return
function calculateSum($a, $b) {
    if (!is_numeric($a) || !is_numeric($b)) {
        return false; // 提前返回
    }
    
    return $a + $b;
}

// 在循环中使用return(函数内)
function findFirstEven($numbers) {
    foreach ($numbers as $number) {
        if ($number % 2 === 0) {
            return $number; // 找到第一个偶数就返回
        }
    }
    return null; // 没找到偶数
}

// 在包含文件中使用return
// config.php
return [
    'database' => [
        'host' => 'localhost',
        'username' => 'root',
        'password' => 'password'
    ],
    'app' => [
        'name' => 'My App',
        'version' => '1.0.0'
    ]
];

// main.php
$config = include 'config.php';
print_r($config);

// 在主脚本中使用return(退出脚本)
if (!extension_loaded('mysqli')) {
    echo "MySQL扩展未安装";
    return; // 退出脚本
}

echo "继续执行...";
?>

3.4 替代语法

3.4.1 条件语句的替代语法

<?php $user = 'admin'; ?>

<!-- HTML模板中的if语句 -->
<?php if ($user === 'admin'): ?>
    <div class="admin-panel">
        <h2>管理员面板</h2>
        <p>欢迎,管理员!</p>
    </div>
<?php elseif ($user === 'user'): ?>
    <div class="user-panel">
        <h2>用户面板</h2>
        <p>欢迎,用户!</p>
    </div>
<?php else: ?>
    <div class="guest-panel">
        <h2>访客面板</h2>
        <p>请先登录</p>
    </div>
<?php endif; ?>

<!-- switch的替代语法 -->
<?php $page = 'home'; ?>
<?php switch ($page): ?>
    <?php case 'home': ?>
        <h1>首页</h1>
        <?php break; ?>
    <?php case 'about': ?>
        <h1>关于我们</h1>
        <?php break; ?>
    <?php default: ?>
        <h1>页面未找到</h1>
<?php endswitch; ?>

3.4.2 循环语句的替代语法

<?php $items = ['苹果', '香蕉', '橙子']; ?>

<!-- foreach的替代语法 -->
<ul>
<?php foreach ($items as $item): ?>
    <li><?= htmlspecialchars($item) ?></li>
<?php endforeach; ?>
</ul>

<!-- for循环的替代语法 -->
<ol>
<?php for ($i = 1; $i <= 5; $i++): ?>
    <li>项目 <?= $i ?></li>
<?php endfor; ?>
</ol>

<!-- while循环的替代语法 -->
<?php $count = 1; ?>
<div>
<?php while ($count <= 3): ?>
    <p>段落 <?= $count ?></p>
    <?php $count++; ?>
<?php endwhile; ?>
</div>

3.5 流程控制最佳实践

3.5.1 避免深层嵌套

<?php
// 不好的写法:深层嵌套
function processUser($user) {
    if ($user !== null) {
        if (isset($user['email'])) {
            if (filter_var($user['email'], FILTER_VALIDATE_EMAIL)) {
                if ($user['age'] >= 18) {
                    if ($user['status'] === 'active') {
                        // 处理用户
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
}

// 好的写法:提前返回
function processUserBetter($user) {
    // 提前检查并返回
    if ($user === null) {
        return false;
    }
    
    if (!isset($user['email'])) {
        return false;
    }
    
    if (!filter_var($user['email'], FILTER_VALIDATE_EMAIL)) {
        return false;
    }
    
    if ($user['age'] < 18) {
        return false;
    }
    
    if ($user['status'] !== 'active') {
        return false;
    }
    
    // 处理用户
    return true;
}

// 更好的写法:使用异常
function processUserBest($user) {
    if ($user === null) {
        throw new InvalidArgumentException('用户不能为空');
    }
    
    if (!isset($user['email'])) {
        throw new InvalidArgumentException('用户邮箱不能为空');
    }
    
    if (!filter_var($user['email'], FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException('用户邮箱格式无效');
    }
    
    if ($user['age'] < 18) {
        throw new InvalidArgumentException('用户年龄必须大于18岁');
    }
    
    if ($user['status'] !== 'active') {
        throw new InvalidArgumentException('用户状态必须为活跃');
    }
    
    // 处理用户
    return true;
}
?>

3.5.2 使用策略模式替代复杂条件

<?php
// 不好的写法:复杂的if-else
function calculateDiscount($customerType, $amount) {
    if ($customerType === 'vip') {
        if ($amount > 1000) {
            return $amount * 0.2;
        } else {
            return $amount * 0.1;
        }
    } elseif ($customerType === 'premium') {
        if ($amount > 500) {
            return $amount * 0.15;
        } else {
            return $amount * 0.08;
        }
    } elseif ($customerType === 'regular') {
        if ($amount > 200) {
            return $amount * 0.05;
        } else {
            return 0;
        }
    } else {
        return 0;
    }
}

// 好的写法:策略模式
interface DiscountStrategy {
    public function calculate($amount);
}

class VipDiscount implements DiscountStrategy {
    public function calculate($amount) {
        return $amount > 1000 ? $amount * 0.2 : $amount * 0.1;
    }
}

class PremiumDiscount implements DiscountStrategy {
    public function calculate($amount) {
        return $amount > 500 ? $amount * 0.15 : $amount * 0.08;
    }
}

class RegularDiscount implements DiscountStrategy {
    public function calculate($amount) {
        return $amount > 200 ? $amount * 0.05 : 0;
    }
}

class DiscountCalculator {
    private $strategies = [];
    
    public function __construct() {
        $this->strategies = [
            'vip' => new VipDiscount(),
            'premium' => new PremiumDiscount(),
            'regular' => new RegularDiscount()
        ];
    }
    
    public function calculate($customerType, $amount) {
        if (!isset($this->strategies[$customerType])) {
            return 0;
        }
        
        return $this->strategies[$customerType]->calculate($amount);
    }
}

$calculator = new DiscountCalculator();
$discount = $calculator->calculate('vip', 1500);
?>

3.5.3 循环优化

<?php
// 避免在循环中进行重复计算
$users = getUsersFromDatabase(); // 假设返回大量用户

// 不好的写法
foreach ($users as $user) {
    if (count($users) > 1000) { // 每次循环都计算count
        // 处理大量用户的逻辑
    }
    processUser($user);
}

// 好的写法
$userCount = count($users);
$isLargeDataset = $userCount > 1000;

foreach ($users as $user) {
    if ($isLargeDataset) {
        // 处理大量用户的逻辑
    }
    processUser($user);
}

// 避免在循环中进行数据库查询
// 不好的写法
foreach ($userIds as $userId) {
    $user = getUserById($userId); // 每次循环都查询数据库
    processUser($user);
}

// 好的写法
$users = getUsersByIds($userIds); // 一次查询获取所有用户
foreach ($users as $user) {
    processUser($user);
}

// 使用生成器处理大数据集
function readLargeFile($filename) {
    $handle = fopen($filename, 'r');
    while (($line = fgets($handle)) !== false) {
        yield trim($line);
    }
    fclose($handle);
}

// 使用生成器,内存占用很小
foreach (readLargeFile('large_file.txt') as $line) {
    processLine($line);
}
?>

3.6 实际应用示例

3.6.1 用户认证系统

<?php
class AuthSystem {
    private $maxAttempts = 3;
    private $lockoutTime = 300; // 5分钟
    
    public function authenticate($username, $password) {
        // 检查用户是否被锁定
        if ($this->isUserLocked($username)) {
            return [
                'success' => false,
                'message' => '账户已被锁定,请稍后再试'
            ];
        }
        
        // 验证用户凭据
        $user = $this->getUserByUsername($username);
        
        if (!$user) {
            $this->recordFailedAttempt($username);
            return [
                'success' => false,
                'message' => '用户名或密码错误'
            ];
        }
        
        if (!password_verify($password, $user['password'])) {
            $this->recordFailedAttempt($username);
            
            $attempts = $this->getFailedAttempts($username);
            $remaining = $this->maxAttempts - $attempts;
            
            if ($remaining <= 0) {
                $this->lockUser($username);
                return [
                    'success' => false,
                    'message' => '密码错误次数过多,账户已被锁定'
                ];
            }
            
            return [
                'success' => false,
                'message' => "密码错误,还有 {$remaining} 次机会"
            ];
        }
        
        // 认证成功,清除失败记录
        $this->clearFailedAttempts($username);
        
        return [
            'success' => true,
            'user' => $user,
            'message' => '登录成功'
        ];
    }
    
    private function isUserLocked($username) {
        $lockTime = $this->getUserLockTime($username);
        
        if (!$lockTime) {
            return false;
        }
        
        return (time() - $lockTime) < $this->lockoutTime;
    }
    
    private function recordFailedAttempt($username) {
        // 记录失败尝试的实现
    }
    
    private function getFailedAttempts($username) {
        // 获取失败次数的实现
    }
    
    private function lockUser($username) {
        // 锁定用户的实现
    }
    
    private function clearFailedAttempts($username) {
        // 清除失败记录的实现
    }
}
?>

3.6.2 数据验证器

<?php
class DataValidator {
    private $errors = [];
    
    public function validate($data, $rules) {
        $this->errors = [];
        
        foreach ($rules as $field => $fieldRules) {
            $value = $data[$field] ?? null;
            
            foreach ($fieldRules as $rule) {
                if (!$this->validateRule($field, $value, $rule)) {
                    break; // 一个字段出错就跳过后续验证
                }
            }
        }
        
        return empty($this->errors);
    }
    
    private function validateRule($field, $value, $rule) {
        switch ($rule['type']) {
            case 'required':
                if (empty($value)) {
                    $this->errors[$field] = $rule['message'] ?? "{$field}不能为空";
                    return false;
                }
                break;
                
            case 'email':
                if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
                    $this->errors[$field] = $rule['message'] ?? "{$field}格式无效";
                    return false;
                }
                break;
                
            case 'min_length':
                if (strlen($value) < $rule['value']) {
                    $this->errors[$field] = $rule['message'] ?? "{$field}长度不能少于{$rule['value']}位";
                    return false;
                }
                break;
                
            case 'max_length':
                if (strlen($value) > $rule['value']) {
                    $this->errors[$field] = $rule['message'] ?? "{$field}长度不能超过{$rule['value']}位";
                    return false;
                }
                break;
                
            case 'numeric':
                if (!is_numeric($value)) {
                    $this->errors[$field] = $rule['message'] ?? "{$field}必须是数字";
                    return false;
                }
                break;
                
            case 'range':
                if ($value < $rule['min'] || $value > $rule['max']) {
                    $this->errors[$field] = $rule['message'] ?? "{$field}必须在{$rule['min']}-{$rule['max']}之间";
                    return false;
                }
                break;
        }
        
        return true;
    }
    
    public function getErrors() {
        return $this->errors;
    }
}

// 使用示例
$validator = new DataValidator();

$userData = [
    'username' => 'john',
    'email' => 'john@example.com',
    'password' => '123456',
    'age' => 25
];

$rules = [
    'username' => [
        ['type' => 'required'],
        ['type' => 'min_length', 'value' => 3],
        ['type' => 'max_length', 'value' => 20]
    ],
    'email' => [
        ['type' => 'required'],
        ['type' => 'email']
    ],
    'password' => [
        ['type' => 'required'],
        ['type' => 'min_length', 'value' => 6]
    ],
    'age' => [
        ['type' => 'numeric'],
        ['type' => 'range', 'min' => 18, 'max' => 100]
    ]
];

if ($validator->validate($userData, $rules)) {
    echo "数据验证通过";
} else {
    echo "数据验证失败:";
    foreach ($validator->getErrors() as $field => $error) {
        echo "$field: $error\n";
    }
}
?>

3.6.3 状态机实现

<?php
class OrderStateMachine {
    const STATE_PENDING = 'pending';
    const STATE_PAID = 'paid';
    const STATE_SHIPPED = 'shipped';
    const STATE_DELIVERED = 'delivered';
    const STATE_CANCELLED = 'cancelled';
    
    private $transitions = [
        self::STATE_PENDING => [self::STATE_PAID, self::STATE_CANCELLED],
        self::STATE_PAID => [self::STATE_SHIPPED, self::STATE_CANCELLED],
        self::STATE_SHIPPED => [self::STATE_DELIVERED],
        self::STATE_DELIVERED => [],
        self::STATE_CANCELLED => []
    ];
    
    public function canTransition($fromState, $toState) {
        return in_array($toState, $this->transitions[$fromState] ?? []);
    }
    
    public function transition($order, $newState) {
        $currentState = $order['status'];
        
        if (!$this->canTransition($currentState, $newState)) {
            throw new Exception("不能从状态 {$currentState} 转换到 {$newState}");
        }
        
        // 执行状态转换前的操作
        switch ($newState) {
            case self::STATE_PAID:
                $this->handlePayment($order);
                break;
                
            case self::STATE_SHIPPED:
                $this->handleShipping($order);
                break;
                
            case self::STATE_DELIVERED:
                $this->handleDelivery($order);
                break;
                
            case self::STATE_CANCELLED:
                $this->handleCancellation($order);
                break;
        }
        
        // 更新订单状态
        $order['status'] = $newState;
        $this->updateOrderInDatabase($order);
        
        return $order;
    }
    
    private function handlePayment($order) {
        // 处理支付逻辑
        echo "处理订单 {$order['id']} 的支付\n";
    }
    
    private function handleShipping($order) {
        // 处理发货逻辑
        echo "处理订单 {$order['id']} 的发货\n";
    }
    
    private function handleDelivery($order) {
        // 处理交付逻辑
        echo "处理订单 {$order['id']} 的交付\n";
    }
    
    private function handleCancellation($order) {
        // 处理取消逻辑
        echo "处理订单 {$order['id']} 的取消\n";
    }
    
    private function updateOrderInDatabase($order) {
        // 更新数据库中的订单状态
        echo "更新订单 {$order['id']} 状态为 {$order['status']}\n";
    }
}

// 使用示例
$stateMachine = new OrderStateMachine();

$order = [
    'id' => 12345,
    'status' => OrderStateMachine::STATE_PENDING,
    'amount' => 100.00
];

try {
    // 订单支付
    $order = $stateMachine->transition($order, OrderStateMachine::STATE_PAID);
    
    // 订单发货
    $order = $stateMachine->transition($order, OrderStateMachine::STATE_SHIPPED);
    
    // 订单交付
    $order = $stateMachine->transition($order, OrderStateMachine::STATE_DELIVERED);
    
    echo "订单处理完成";
} catch (Exception $e) {
    echo "错误:" . $e->getMessage();
}
?>

3.7 小结

本章详细介绍了PHP的控制结构:

  1. 条件语句:if、switch、三元运算符、match表达式
  2. 循环语句:for、while、do-while、foreach
  3. 跳转语句:break、continue、goto、return
  4. 替代语法:适用于HTML模板的语法
  5. 最佳实践:避免深层嵌套、使用策略模式、循环优化
  6. 实际应用:认证系统、数据验证、状态机等

3.8 实践练习

  1. 条件语句练习

    • 编写一个成绩等级判断程序
    • 实现一个简单的计算器
    • 创建一个用户权限检查系统
  2. 循环语句练习

    • 打印各种图案(三角形、菱形等)
    • 实现冒泡排序算法
    • 编写文件处理程序
  3. 综合练习

    • 实现一个简单的菜单系统
    • 编写数据验证类
    • 创建一个状态机
  4. 优化练习

    • 重构深层嵌套的代码
    • 优化循环性能
    • 使用设计模式改进条件判断

3.9 扩展阅读

  1. PHP控制结构官方文档
  2. 代码整洁之道
  3. 重构:改善既有代码的设计
  4. 设计模式:可复用面向对象软件的基础
  5. PHP最佳实践

下一章预告:在下一章中,我们将学习PHP的函数,包括函数定义、参数传递、作用域、匿名函数等内容。