PHP面试重在真实场景应用:如用单例管数据库连接、array_merge_recursive合并配置、strpos必须用!==false防误判,而非手写复杂算法。

PHP面试里基础算法和设计模式不是用来考你手写红黑树的,而是看你能不能在真实场景里识别问题、选对工具、避开坑。真正在意的是:你改一段用户登录逻辑时,会不会下意识用单例管数据库连接;处理一堆配置项合并时,是不是第一反应就想到 array_merge_recursive 而不是 +;遇到字符串位置判断,有没有条件反射检查 strpos 返回的是 false 还是 0。
strpos 返回 0 却被 if 判为 false 怎么办
这是高频翻车点。因为 strpos 找到子串在开头(索引 0)时返回整数 0,而 PHP 的 if 会把 0 当成 false,导致逻辑误判。
- 错误写法:
if (strpos($haystack, $needle)) { ... } - 正确写法必须用严格比较:
if (strpos($haystack, $needle) !== false) { ... } - 别用
== true或=== true——strpos从不返回布尔值,只返回整数或false - 如果只是要判断“是否存在”,且不关心位置,可用
str_contains($haystack, $needle)(PHP 8.0+),它直接返回布尔值,没歧义
array_merge 和 + 合并数组的区别在哪
这两个操作看着像,但行为完全不同,尤其在关联数组和重复键场景下容易出错。
-
array_merge($a, $b):数值键重排,关联键后出现的覆盖前面的。例如['a' => 1] + ['a' => 2]得['a' => 1];而array_merge(['a' => 1], ['a' => 2])得['a' => 2] -
$a + $b:只保留左边数组的键,右边同名键被忽略。适合“默认配置 + 用户配置”这种优先级明确的合并 - 若要递归合并(比如多层配置),得用
array_merge_recursive,但它对相同键的值不是覆盖而是“装进数组”,可能意外产生嵌套 - PHP 7.4+ 可用展开语法:
[...$a, ...$b],但仅适用于数值索引数组,关联键会丢失
单例模式为什么常被滥用?什么场景真该用
面试官问单例,不是想听你背定义,而是看你懂不懂它的代价和边界。
立即学习“PHP免费学习笔记(深入)”;
- 典型误用:给每个服务类都套个单例外壳,以为“省资源”。其实对象本身不重,但全局状态会让单元测试变脆弱、并发逻辑难推理
- 真正合理场景只有两个:
数据库连接(PDO 实例开销大,且连接池意义有限)、日志处理器(避免多个文件句柄争抢) - PHP-FPM 模式下,单例生命周期 = 单次请求,不是跨请求持久化,这点很多人混淆
- 替代方案更推荐依赖注入容器(如
ContainerInterface),它能控制实例复用策略,比硬编码单例灵活得多
递归遍历目录时怎么防无限循环
用 scandir 或 RecursiveDirectoryIterator 遍历时,符号链接(symlink)可能形成环路,导致脚本卡死或爆栈。
- 最简单办法:初始化
RecursiveDirectoryIterator时传入标志FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS是危险的,必须去掉FOLLOW_SYMLINKS - 手动检测路径是否已访问过:用绝对路径做键存进数组,每次进入新目录前先
realpath()并查重 - 设深度限制比防环更实际:
setMaxDepth(5),大多数项目根本不需要扫太深 - 注意
glob('**')在 PHP 7.1+ 默认不跟随软链,但旧版本需显式加GLOB_NOFollow
算法和设计模式在 PHP 里从来不是炫技点,而是你读别人代码时能一眼看出“这里用单例其实是掩盖了配置混乱”,或者改需求时知道“这个 strpos 必须补 !== false,否则上线就丢数据”。细节不声不响,但决定交付质量。



















