李东's Blog

李东

php最新面试题

php最新面试题

# 中级 PHP 面试抗追问手册(武汉 1w 档)终极版 > 说明:全是“人话版”,面试官追问 3~4 层也能站住。 > 每题包含:面试官问 → 人话答 → 追问 → 活法提示。 > 适合打印、背诵和电脑复习。 --- ## 目录 1. 百万数据量优化 2. Laravel 启动流程 3. Redis 缓存击穿 / 数据一致 4. N+1 查询(Laravel) 5. 队列(Laravel) 6. Linux / 部署 7. 空窗期 + OpenClaw 8. 高并发接口设计 9. 秒杀 / 抢购设计 10. 接口幂等设计 11. 分库分表设计 12. AI 辅助开发工具(Cursor / Trae / OpenClaw) --- ## 百万数据量怎么优化 ### 第一问 **面试官**:百万数据量的 SQL 怎么优化? **答法**:从数据库、代码、缓存三个层面做。 ### 第二问(追) **面试官**:索引你怎么建的? **答法**:先看最频繁的 SQL,再按 where + order by 建联合索引,避免单字段索引,索引不要越多越好。 ### 第三问(追) **面试官**:分页你怎么做? **答法**:数据量大不用 offset 分页,用 id 游标分页:`where id > last_id limit 20`。 ### 第四问(杀) **面试官**:排序怎么办? **答法**:排序字段 + 查询条件在索引里,避免回表。 ### ⚠️ 作死点 - select * - 单字段索引不够 - offset 翻页过大 ### ✅ 活法关键词 - 联合索引 - 游标分页 - 三层思路(DB/代码/缓存) --- ## Laravel 启动流程 ### 第一问 **面试官**:Laravel 启动流程? **答法**: 1. `public/index.php` 入口 2. Composer 自动加载 3. Application 容器初始化 4. 核心 ServiceProvider 注册(数据库、缓存、日志) 5. 全局中间件 + 路由中间件 6. 路由分发 → 控制器 → 模型 ### 第二问(追) **面试官**:中间件什么时候执行? **答法**:路由匹配后,先全局中间件,再路由中间件,控制器前执行。 ### 第三问(追) **面试官**:ServiceProvider 是干嘛的? **答法**:初始化系统入口,绑定接口、注册事件、加载配置,全局逻辑不适合放控制器里。 ### 第四问(杀) **面试官**:Middleware 和 Provider 什么时候用? **答法**:请求相关用 Middleware,系统启动阶段用 Provider。 ### ⚠️ 作死点 - 背诵教材术语 - “就是注册服务”一句带过 ### ✅ 活法关键词 - IOC 容器 - 请求链中间件 - Provider 初始化 --- ## Redis 缓存击穿 / 数据一致 ### 第一问 **面试官**:缓存击穿怎么办? **答法**:加锁,防止多个请求同时查数据库。 ### 第二问(追) **面试官**:具体怎么加锁? **答法**:缓存 miss 后用 `setnx` 或原子操作,只让一个请求去查数据库。 ### 第三问(追) **面试官**:其他请求怎么办? **答法**:等一小会,或者返回旧缓存,不让数据库被打爆。 ### 第四问(杀) **面试官**:数据不一致怎么办? **答法**:以数据库为准,更新时先改库再删缓存,允许短暂不一致。 ### ⚠️ 作死点 - 不考虑高并发 - 背空话 “分布式锁” ### ✅ 活法关键词 - setnx / 原子操作 - 数据库为准 - 短暂不一致可接受 --- ## N+1 查询(Laravel) ### 第一问 **面试官**:遇到过 N+1 查询吗? **答法**:遇到过,列表循环关联表容易踩。 ### 第二问(追) **面试官**:怎么发现的? **答法**:慢 SQL / 日志 / 开发调试发现。 ### 第三问(追) **面试官**:怎么解决? **答法**:用 `with()` 一次性查出关联数据,避免循环查询数据库。 ### ⚠️ 作死点 - 不查日志 - 循环里查数据库 ### ✅ 活法关键词 - eager loading - with() - 慢 SQL --- ## 队列(Laravel) ### 第一问 **面试官**:你用过队列吗? **答法**:用过,发邮件、消息等异步任务。 ### 第二问(追) **面试官**:为什么不用同步? **答法**:同步拖慢接口响应,影响用户体验。 ### 第三问(追) **面试官**:队列失败了怎么办? **答法**:失败重试,超过次数进失败队列,人工或定时处理。 ### ⚠️ 作死点 - 队列就是异步,不说失败处理 - 不提延迟/重试机制 ### ✅ 活法关键词 - 异步任务 - 失败队列 - 重试机制 --- ## Linux / 部署 ### 第一问 **面试官**:怎么部署项目? **答法**:Linux + Nginx + PHP-FPM ### 第二问(追) **面试官**:PHP-FPM 挂了怎么办? **答法**:看日志 → 重启服务 → 排查内存或慢请求 ### 第三问(追) **面试官**:怎么防止老挂? **答法**:控制并发,优化慢接口,避免单请求耗时过长。 ### ⚠️ 作死点 - 不看日志 - 只重启不查原因 ### ✅ 活法关键词 - 日志 - 并发控制 - 慢接口优化 --- ## 空窗期 + OpenClaw ### 第一问 **面试官**:你这段时间没上班,在干嘛? **答法**:整理以前项目技术点,同时用 OpenClaw 做自动化任务,例如定时采集数据、同步数据库。 ### ⚠️ 作死点 - 说“自学” - 编公司 ### ✅ 活法关键词 - 技术整理 - 自动化 - OpenClaw 实战 --- ## 高并发接口设计 ### 第一问 **面试官**:高并发接口你怎么设计? **答法**:先从限流、缓存、队列三方面考虑,保证接口在高流量下不会崩。 ### 第二问(追) **面试官**:限流你具体怎么做? **答法**:用 Redis 计数器或者漏桶/令牌桶算法,对接口做 QPS 限制。 ### 第三问(追) **面试官**:缓存策略呢? **答法**:热点数据放 Redis,非核心数据用延迟更新或异步刷新,避免缓存击穿。 ### 第四问(杀) **面试官**:队列处理失败怎么办? **答法**:失败重试,超过次数进失败队列,人工或定时处理。 ### ⚠️ 作死点 - 不考虑限流 - 全靠数据库撑 - 队列失败不处理 ### ✅ 活法关键词 - 限流算法 - Redis 热点缓存 - 队列重试 --- ## 秒杀 / 抢购设计 ### 第一问 **面试官**:你做过秒杀系统吗? **答法**:有做过,核心是控制库存、限流和抢购请求排队。 ### 第二问(追) **面试官**:如何保证库存不超卖? **答法**:用 Redis 原子操作减库存,同时异步落库。 ### 第三问(追) **面试官**:并发特别高怎么办? **答法**:前端请求排队到队列中处理,减少数据库压力;热点缓存防击穿。 ### 第四问(杀) **面试官**:如果队列挂了怎么办? **答法**:落库后重试失败队列或手工干预,保证最终一致性。 ### ⚠️ 作死点 - 数据库直接减库存 - 没限流、没排队 ### ✅ 活法关键词 - Redis 原子减库存 - 异步队列 - 高并发排队 --- ## 接口幂等设计 ### 第一问 **面试官**:接口怎么保证幂等? **答法**:使用唯一请求 ID 或 token,重复请求不重复写数据库。 ### 第二问(追) **面试官**:支付类接口怎么办? **答法**:先生成订单号,接口幂等校验 ID,操作数据库前检查是否已存在,保证重复请求不重复扣款。 ### 第三问(追) **面试官**:Redis 怎么帮忙? **答法**:请求 ID 可以缓存到 Redis,短时间重复请求直接返回结果,不访问数据库。 ### ⚠️ 作死点 - 只靠数据库约束 - 不考虑重复请求 ### ✅ 活法关键词 - 请求唯一 ID - Redis 幂等缓存 - 支付安全 --- ## 分库分表设计 ### 第一问 **面试官**:你的项目如何分库分表? **答法**:按业务或时间拆表、拆库,减少单表压力。 ### 第二问(追) **面试官**:如何路由请求? **答法**:通过中间件或 DAO 层判断 user_id 或时间,选择对应库和表。 ### 第三问(追) **面试官**:事务怎么保证? **答法**:跨库事务尽量避免,核心业务用单库事务,其他用最终一致性策略。 ### 第四问(杀) **面试官**:数据迁移怎么办? **答法**:用脚本批量迁移 + 双写策略,保证新老系统过渡期数据一致。 ### ⚠️ 作死点 - 全靠单库撑 - 跨库事务处理复杂不说 - 不做迁移策略 ### ✅ 活法关键词 - 分库分表 - 中间件路由 - 单库事务 + 最终一致性 --- ## AI 辅助开发工具(Cursor / Trae / OpenClaw) ### 第一问 **面试官**:你了解 Cursor、Trae、OpenClaw 这些 AI 工具吗? **答法**:了解,我平时用这些工具来提升开发效率和自动化运维。 - **Cursor**:代码生成与智能补全,快速生成函数模板,提高开发速度。 - **Trae**:AI 辅助测试和调试,分析代码问题和优化建议。 - **OpenClaw**:自动化数据采集和任务调度,重复操作交给工具做。 ### 第二问(追) **面试官**:能具体举个例子你是怎么用的吗? **答法**: - Cursor:Laravel 控制器快速生成 CRUD 方法 - Trae:跑单元测试分析日志发现潜在 bug - OpenClaw:定时采集第三方数据,同步数据库 ### 第三问(追) **面试官**:那你怎么保证 AI 生成的代码没问题? **答法**:AI 只做辅助,核心逻辑和数据库操作我都会手动 review,必要时重写或优化。 ### 第四问(杀) **面试官**:AI 能替代你开发吗? **答法**:AI 只能辅助,不能替代设计思路、业务判断和复杂逻辑开发。 ### ⚠️ 作死点 - 说“全交给 AI 做” - 不区分辅助和核心逻辑 - 只说工具名,不讲应用场景 ### ✅ 活法关键词 - AI 辅助开发 - 自动化任务 - 代码生成 / 测试 / 数据采集 - 最终逻辑把控在自己手里
php
17
2026-03-01
phpstorm破解版教程

phpstorm破解版教程

1. 先下载一个2024的PHPstorm版本 然后通过链接下载顶部的扩展包 [下载链接]( https://3.jetbra.in/ "下载链接") [![](https://lidong.cc/uploads/images/2025-07-25/20250725191448987.png)](https://lidong.cc/uploads/images/2025-07-25/20250725191448987.png) ###### 下载之后解压放到D盘文件夹下面下载之后解压放到D盘文件夹下面 ![](https://lidong.cc/uploads/images/2025-07-25/20250725191604527.png) ###### 然后打开PHPstrom安装目录 找到phpstorm64.exe.vmoptions这个文件 ![](https://lidong.cc/uploads/images/2025-07-25/20250725191537591.png) ###### 把下面这三行代码放到这个文件最底部 ![](https://lidong.cc/uploads/images/2025-07-25/20250725191643571.png) ``` --add-opens=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED --add-opens=java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED -javaagent:D:\jetbra\ja-netfilter.jar=jetbrains``` ###### 保存代码之后 重启phpstorm 然后在链接里面复制激活码 即可激活使用 ![](https://lidong.cc/uploads/images/2025-07-25/20250725191709832.png)![](https://lidong.cc/uploads/images/2025-07-25/20250725191723506.png)
php
710
2025-07-25
JS来判断未操作直接退出账户

JS来判断未操作直接退出账户

<script type="text/javascript"> var lastTime = new Date().getTime(); var currentTime = new Date().getTime(); var timeOut = 10 * 60 * 1000; //设置超时时间: 10分 $(function(){ /* 鼠标移动事件 */ $(document).mouseover(function(){ lastTime = new Date().getTime(); //更新操作时间 }); }); function testTime(){ currentTime = new Date().getTime(); //更新当前时间 if(currentTime - lastTime > timeOut){ //判断是否超时 $.ajax({ url:"{{}}",//走退出接口 dataType:"json", type:"get", async : false, cache : false, success:function(){ // debugger; window.location.href="{{'admin/login'}}"; }, error:function(){ } }) } } /* 定时器 间隔1秒检测是否长时间未操作页面 */ window.setInterval(testTime, 1000); </script>
php
980
2025-04-01
使用API接口签名的代码

使用API接口签名的代码

//签名 function sin($params){ ksort($params); $str = ''; foreach ($params as $key => $param) { if ($param === '') continue; $param=urlencode($param); $str .= (empty($str) ? '' : '&') . "{$key}={$param}"; } // $str.='channelcode='.$params['channelcode'].'&productcode='.$params['productcode'].'&orderno='.$params['orderno'].'&appsecret=Mi1TtL0YyQbqom3xQjOrT2RD7KCPHmel'; $str.='&Mi1TtL0YyQbqom3xQjOrT2RD7KCPHmel'; $md5 = md5($str); return $md5; }
php
994
2025-04-01
hyperf框架热更新

hyperf框架热更新

### hyperf框架修改代码之后 实时监听然后自动重启 Watcher composer来安装扩展 composer require hyperf/watcher --dev 配置 php bin/hyperf.php vendor:publish hyperf/watcher 运行 php bin/hyperf.php server:watch
php
1233
2024-12-15
Go部署到linux服务器

Go部署到linux服务器

###普通部署 set GOARCH=amd64 set GOOS=linux go build main.go //打包 然后传到线上对应的文件夹 给777权限 我们可以用nohup ./main &命令让程序在后台运行 nohup ./main & 查看程序是否正常运行 ps aux|grep main 关闭项目 用Kill PID 就行了 域名 用nginx 配置代理 映射到对应的IP 端口上去就可访问 location / { proxy_pass http://127.0.0.1:8000; proxy_http_version 1.1; #proxy_cache_bypass $http_upgrade; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; } ###Beego部署 如果bee run 出现报错 重新下载第三方包:go mod tidy 打包部署 bee pack -be GOOS=linux (打包到linux上部署命令) bee pack -be GOOS=window (打包到windows上部署命令) 将压缩包传到服务器gopath目录下,进行解压 nohup 用途:不挂断地运行命令。
php
1274
2024-12-15
laravel Orderby排序0不参与

laravel Orderby排序0不参与

laravel Orderby排序的时候 数据库有0值 不参与排序 USER::OrderByRaw('is_zhi_num=0,is_zhi_num')->get(); ![](https://lidong.cc/uploads/images/2022-07-24/20220724212514253.jpg)
php
1182
2024-12-07
php使用Redis限制IP访问次数

php使用Redis限制IP访问次数

## 使用Redis限制IP访问次数 <?php $redis = new Redis(); $redis->connect('127.0.0.1', 6379); //连接 Redis if (!$redis->exists(get_real_ip())){ //第一次访问 $redis->set(get_real_ip(),1,5*60); // 设置5分钟过期时间并设置初始值1 }else{ //已经记录过IP if ($redis->get(get_real_ip())<30){ //判断IP有没有到达拉黑阈值 $redis->incr(get_real_ip()); //次数加一 }else{ echo '请稍后访问!';exit; } } function get_real_ip($type = 0,$adv=false) { $type = $type ? 1 : 0; static $ip = NULL; if ($ip !== NULL) return $ip[$type]; if($adv){ if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); $pos = array_search('unknown',$arr); if(false !== $pos) unset($arr[$pos]); $ip = trim($arr[0]); }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; }elseif (isset($_SERVER['REMOTE_ADDR'])) { $ip = $_SERVER['REMOTE_ADDR']; } }elseif (isset($_SERVER['REMOTE_ADDR'])) { $ip = $_SERVER['REMOTE_ADDR']; } $long = sprintf("%u",ip2long($ip)); $ip = $long ? array($ip, $long) : array('0.0.0.0', 0); return $ip[$type]; }
php
1274
2024-12-07