CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
PHP Web 入门/课时/基础语法
RawBlame
课时目录12 节

PHP Web 入门

  1. 01PHP 是什么
  2. 02基础语法
  3. 03函数与命名空间
  4. 04面向对象
  5. 05Composer 依赖
  6. 06Web 请求处理
  7. 07PDO 与 MySQL
  8. 08REST API 风格
  9. 09PHP 8 新特性
  10. 10Docker 运行 PHP
  11. 11PHP vs Java 选型
  12. 12综合练习

基础语法

变量、数组、控制流、类型。

35 分钟

基础语法

这一课你将能做到

  1. 用正确的变量、字符串、数组语法写出结构清晰的 PHP 脚本
  2. 熟练使用 if/match/foreach 等控制流处理一组数据并输出结果
  3. 用类型声明和 strict_types 让 PHP 写出接近静态语言的严谨风格

为什么要学

变量、数组、控制流、类型声明是任何语言的「地基四件套」。PHP 的特殊之处在于:它是动态类型语言,但 PHP 7 之后引入了完整的类型声明体系,PHP 8 又补上了 match 表达式、命名参数等现代语法。今天企业级 PHP 项目的规范(如 Laravel 框架源码、PSR 标准)都大量使用类型声明——只会写无类型的「老式 PHP」,在现代代码库里寸步难行。

人话:这节课就是把「会打字」练到「会写文章」。学完你就能独立写一个处理数组的统计脚本、按条件分流的业务判断,这是后面函数、面向对象、数据库操作的全部前提。

先建立图像

PHP 变量的心智模型:带 $ 前缀的标签,贴在值上。

$price  ──►  19.9        (float)
$name   ──►  "Spring"    (string)
$tags   ──►  [0]=>'php'  (array,有序键值对容器)
              [1]=>'web'

和 Java 最大的区别:变量本身没有类型,值才有类型;把字符串赋给 $price 也不报错。但开启类型声明后,你可以在函数签名、类属性上重新找回静态检查。

跟着做

步骤 1:变量与字符串

新建 vars.php:

<?php
declare(strict_types=1);

$name = 'Spring';
$price = 19.9;
$active = true;

// 双引号支持变量插值,单引号是纯字面量
echo "框架名:{$name},价格:{$price}\n";
echo '框架名:{$name}\n';          // 原样输出 {$name}
echo $name . ' Boot' . PHP_EOL;    // 点号拼接字符串

执行 php vars.php。记住两条铁律:变量以 $ 开头、双引号才插值。

步骤 2:类型声明初体验

<?php
declare(strict_types=1);

function add(int $a, int $b): int {
    return $a + $b;
}

echo add(2, 3), PHP_EOL;      // 5
echo add(2.5, 3);             // TypeError!严格模式下浮点数不能传给 int

declare(strict_types=1) 必须是文件第一条语句,只对当前文件生效。开了它,传参类型不符直接抛 TypeError;不开,PHP 会做宽松转换(如 "5" 转成 5),隐患更深。

步骤 3:数组——PHP 的万能容器

<?php
declare(strict_types=1);

// 索引数组
$stack = ['PHP', 'Go', 'Java'];
$stack[] = 'Rust';                    // 追加元素
echo count($stack), PHP_EOL;          // 4
echo $stack[0], PHP_EOL;              // PHP

// 关联数组(类似 Java 的 Map)
$user = ['id' => 1, 'name' => '张三', 'roles' => ['admin', 'dev']];
echo $user['name'], PHP_EOL;          // 张三
echo $user['roles'][1], PHP_EOL;      // dev

// 遍历
foreach ($user as $key => $value) {
    if (is_array($value)) {
        echo $key, ': ', implode(',', $value), PHP_EOL;
    } else {
        echo $key, ': ', $value, PHP_EOL;
    }
}

PHP 数组 = 索引数组 + 字典二合一,底层是有序哈希表。写惯 Java 的人注意:不存在单独的 Map 类型,关联数组就是 Map。

步骤 4:控制流

<?php
declare(strict_types=1);

$scores = ['php' => 92, 'mysql' => 78, 'nginx' => 85];

foreach ($scores as $subject => $score) {
    // match 表达式(PHP 8+):有返回值、严格比较、不需要 break
    $level = match (true) {
        $score >= 90 => '优秀',
        $score >= 80 => '良好',
        $score >= 60 => '及格',
        default      => '不及格',
    };
    printf("%-6s %d 分,评级 %s\n", $subject, $score, $level);
}

// ?: 三元与 ?? 空合并:处理可能不存在的键
$page = (int) ($_GET['page'] ?? 1);   // CLI 下 $_GET 不存在,取默认值 1
echo "当前页码:{$page}\n";

match(true) 配合条件写法,可读性远超嵌套 if-else;?? 专门对付「键可能不存在」的场景,比 isset() ? : 简洁得多。

讲清楚要点

  1. == 宽松比较是历史大坑:0 == "foo" 在 PHP 8 前为 true。PHP 8 修复了字符串与数字比较的规则,但面试和遗留代码里它仍是高频坑点。规则很简单:一律用 ===,除非明确要做弱比较。
  2. strict_types 按文件声明:只约束「调用发生在这个文件里」的传参行为,不全局生效。团队项目应在所有源码文件顶部统一声明。
  3. 数组是有序哈希表:键顺序即插入顺序,foreach 按插入顺序遍历;数字键会自动重排(array_values),字符串键保留。unset($arr[1]) 不会让后面的键前移。
  4. 类型声明金字塔:参数类型 → 返回类型 → 可空类型 ?int → 联合类型 int|string(PHP 8.0)→ 交叉类型 Countable&Traversable(PHP 8.1)。按项目规范从参数和返回值开始加,收益最大。

你可能会懵的地方

  • $a 和 &$a 有什么区别? $a 是值拷贝(写时复制,实际开销不大),&$a 是引用传递,函数内修改会影响外部。foreach ($arr as &$v) 也用引用修改原数组,但循环后必须 unset($v),否则后续复用 $v 会误改最后一个元素。
  • 关联数组的键有什么限制? 整型和字符串作键;浮点数键会被截断成整型;true/false/null 会转成 1/0/""。数字字符串键如 "8" 会自动转成数字键 8。
  • 单引号和双引号到底怎么选? 需要插值或转义符(\n、\t)用双引号;纯字面量用单引号更快更安全。字符串里带 $ 时务必想清楚是否会被当成变量解析。
  • switch 和 match 该用哪个? 新代码统一用 match:它是表达式(有返回值)、用 === 严格比较、不需要 break、漏分支直接抛异常而不是静默掉过。switch 只在维护遗留代码时阅读即可。
  • 为什么我的 foreach 改了元素但数组没变? foreach ($arr as $v) 中 $v 是拷贝。要改原数组用引用:foreach ($arr as &$v) { $v = $v * 2; },循环后 unset($v)。

错法对照

错法问题正解
if ($status == '1') 弱比较"1"、1、true 混淆统一用 === 严格比较
单引号里写 "$name"不插值,原样输出改用双引号或点号拼接
array(1, 2, 3) 老式写法冗长过时用短语法 [1, 2, 3]
未声明 strict_types 就依赖隐式转换"abc" == 0 类隐患文件顶部 declare(strict_types=1)
函数里 if($a){return A;}else{return B;}嵌套冗长提前 return 或用 match 表达式
foreach 引用循环后不 unset后续误改最后一项循环结束立即 unset($v)

卡点急救

  1. Parse error: syntax error, unexpected ...:多半是少了分号、括号没闭合、把 . 写成 +(PHP 字符串拼接用点号)。按报错行号检查上一行结尾。
  2. Undefined array key "page" 警告:访问了不存在的键。用 $arr['key'] ?? 默认值 或先 isset() / array_key_exists() 判断。
  3. 数组明明有值却取不到:检查键类型——数字键 0 和字符串键 "0" 是同一个键,但 " 0"(带空格)不是;用 var_dump($arr) 看真实结构。

面试常问

  • == 和 === 的区别? == 先做类型转换再比较(PHP 8 收紧了数字与字符串比较规则),=== 同时比较类型和值。生产代码规范要求一律 ===,避免 0 == "abc" 这类历史陷阱。
  • PHP 数组的底层实现是什么? 有序哈希表(HashTable):通过哈希表实现 O(1) 键查找,同时维护插入顺序支持索引语义;数字键和字符串键统一处理。这也是 PHP 数组既是 list 又是 map 的原因。
  • strict_types 的作用范围是什么? declare(strict_types=1) 只对声明它的文件生效,影响该文件内发起的函数调用与方法调用的参数/返回值类型检查;不含该声明的文件调用同一函数仍是宽松模式,因此团队必须在编码规范里强制统一。

自测三问

  1. match 表达式相比 switch 有哪四个优点?
  2. 如何安全地读取一个可能不存在的数组键并给默认值?
  3. PHP 关联数组等价于 Java 的哪个结构?底层如何做到有序?

小结一句话

PHP 基础语法 = $ 变量 + 万能数组 + 现代控制流(match/??),再用 strict_types 和类型声明把动态语言管出静态纪律。

延伸

  • PHP 官方手册:类型
  • 下一课:函数与命名空间——从脚本堆砌走向可复用、可自动加载的工程代码。
加载本节练习…
← 上一课PHP 是什么下一课 →函数与命名空间