1.2 语法基础:请求处理的第一套动作 本节摘要:变量、类型、运算符与控制结构是 PHP 接待请求的第一套动作。本节不背语法表,而是沿一份表单数据的处理流程把这些语法串起来:数字被提交上来是字符串,弱类型比较会埋雷,分支负责分拣,循环负责成批作业,match 负责干净的多路分发。读完你应当能写出结构清晰、类型边界清楚的请求处理代码。 先从一份表单数据说起 假设月台收到一份报名表单,旅客提交了姓名与年龄。1.7 节会专门讲表单怎么接收,这里先约定数据已经拿到手,聚焦"拿到之后怎么处理"。请看第一段代码,注意注释里标出的实际类型: 这段代码里藏着本节最重要的一个事实:表单、URL 参数、Cookie 送来的值一律是字符串。数值运算前要不要转换、怎么转换,是每个服务端新手都要过的第一道坎。
本节摘要:变量、类型、运算符与控制结构是 PHP 接待请求的第一套动作。本节不背语法表,而是沿一份表单数据的处理流程把这些语法串起来:数字被提交上来是字符串,弱类型比较会埋雷,分支负责分拣,循环负责成批作业,match 负责干净的多路分发。读完你应当能写出结构清晰、类型边界清楚的请求处理代码。
假设月台收到一份报名表单,旅客提交了姓名与年龄。1.7 节会专门讲表单怎么接收,这里先约定数据已经拿到手,聚焦"拿到之后怎么处理"。请看第一段代码,注意注释里标出的实际类型:
<?php $raw = $_POST['age'] ?? '18'; // 表单来的值永远是字符串或 null var_dump($raw); // string(2) "18" —— 注意,是字符串 $age = (int) $raw; // 显式转成整数,边界在这里说清楚 var_dump($age); // int(18) if ($age >= 18) { echo "允许进站\n"; } else { echo "需要成人陪同\n"; }
这段代码里藏着本节最重要的一个事实:表单、URL 参数、Cookie 送来的值一律是字符串。数值运算前要不要转换、怎么转换,是每个服务端新手都要过的第一道坎。PHP 的弱类型会替你自动转换('18' >= 18 成立),便利但有代价,下面专门说。
变量以 $ 开头,无需声明类型,赋什么就是什么。基础类型有字符串、整数、浮点、布尔、数组、对象与 NULL,其中数组与对象分别交给 1.4 和 2.1 展开,这里看标量。弱类型的便利在于省事,代价在于两类经典事故。
第一类是比较运算符的选择。松散比较 == 会先做类型转换再比,严格比较 === 要求类型与值都对上。看一组真实的坑:
var_dump(0 == 'adult'); // PHP 8 之前为 true(字符串转数字得 0),8 起为 false var_dump('' == null); // true:空串、null、0、'0' 在布尔语境里都是"假" var_dump('18' === 18); // false:类型不同,直接不等 // 改进写法:入口先定类型,内部一律严格比较 $page = (int) ($_GET['page'] ?? 1); if ($page === 1) { echo "回第一页\n"; }
第二类是隐式转换的精度问题。金额计算用浮点会出错,0.1 + 0.2 !== 0.3 在大多数语言里都成立,PHP 也不例外。工程上的规矩是:金额用整数分或字符串配合数学扩展处理,永远别拿浮点直接比对。写业务代码时把这三条记牢,能省掉一大半"灵异 bug"。
PHP 8 允许在文件头声明严格类型,让函数参数与返回值不再自动转换:
<?php declare(strict_types=1); function fare(int $km, float $pricePerKm): float { return $km * $pricePerKm; } echo fare(12, 0.8), "\n"; // 9.6 // fare('12', '0.8'); // 严格模式下抛 TypeError,不再悄悄转换
我的建议是:新项目一律开严格声明。它把类型错误从"运行到一半才暴露的暗病"变成"调用瞬间就报错的明病",排错成本骤降。
分支负责分拣。if、elseif、else 是主力,写法上有个小建议:正向条件优先,避免 if (!$ok) {... else ...} 这种绕弯结构。多路分发在 PHP 8 里首选 match 表达式,它比 switch 干净——严格比较、无穿透、有返回值:
<?php $status = 404; $message = match (true) { $status >= 200 && $status < 300 => '通行正常', $status === 404 => '站台不存在', $status === 500 => '月台故障,正在抢修', default => '未知状态', }; echo $message, "\n"; // 站台不存在
循环负责成批作业。数组遍历几乎总是用 foreach,它同时支持取值与取键:
<?php $luggages = ['背包' => '已过安检', '行李箱' => '待检', '纸箱' => '已过安检']; foreach ($luggages as $item => $state) { if ($state !== '已过安检') { echo "{$item} 还没过检,安排复检\n"; } } // 输出:行李箱 还没过检,安排复检
for 适合明确的次数循环,while 适合"满足条件才继续"的场景,比如逐行读取日志文件(1.6 节会用到)。跳出循环用 break,跳过本轮用 continue,两者别滥用——嵌套超过两层的循环加 continue,读起来就像听广播里的绕口令,多半该拆函数了(见 1.3)。
运算符层面再点两个服务端常用的:字符串拼接用点号 .,PHP 8.4 起也可以用管道风格写法但点号仍是主流;空合并 ?? 专门对付"可能不存在的输入",$_GET['page'] ?? 1 一行顶过去一串 isset 判断,处理请求参数时几乎离不开它。
把前面的语法件组装成一个小而完整的处理流程,这也是 1.7 节表单处理的预演:
<?php declare(strict_types=1); $name = trim($_POST['name'] ?? ''); // 去掉首尾空白 $age = (int) ($_POST['age'] ?? 0); $errors = []; if ($name === '') { $errors[] = '姓名不能为空'; } if ($age < 1 || $age > 120) { $errors[] = '年龄不在合理范围'; } if ($errors) { foreach ($errors as $e) { echo "退件:{$e}\n"; } exit(1); } echo "受理成功:{$name},{$age} 岁\n"; // 命令行模拟请求:php form.php 可先跑通分支, // 接入网页后同样的逻辑由表单提交触发
操作顺序、分支走向、失败出口都摆在一个文件里。建议亲手跑两遍:一遍喂合法数据,一遍故意把年龄填成零,观察两条出口各自的输出。校验逻辑以后会不断变厚,但这个"收集错误、统一退件"的骨架不会变。
⚠️ 拿
==比较用户输入与数字:PHP 8 已经修掉最离谱的转换,但松散比较依旧是隐患,输入定完类型后请一律===。⚠️ 忘了表单值是字符串:直接把
$_POST['age']拿去算术运算,某些路径下会得到意外结果,入口处显式转换最稳。
strict_types,比较一律 ===,把类型问题扼杀在调用瞬间。下一节把重复出现的处理动作封装成函数——班组一旦编好,月台上就不必每次现拉人手。