
360春招那场笔试我到现在还记得第一屏客观题弹出来时的压迫感PHP基础、Web安全、数据库、网络协议什么都在考而且选择题的量比想象中大得多。很多人拿到“客观题合集”这五个字以为刷一遍语法题就够了真上了考场才发现360的客观题考的不是“会不会”而是“熟不熟”——同样的知识点换一个问法换一组干扰项就是一道新题。这篇文章我不打算给你整理一份“360真题答案表”那东西网上到处都是背了也没用。我想做的是另一件事把2018春招这套笔试客观题背后的考察逻辑拆开看看360作为一家以安全为核心的技术公司在PHP开发工程师这个岗位上到底想筛选什么样的人。如果你正准备投PHP开发岗或者已经在刷题阶段这篇文章可以帮你把复习方向从“背题”扭转到“理解命题人意图”上来。1. 360笔试客观题的考察范围与出题逻辑1.1 客观题在整场笔试中的定位不是送分题是筛选器很多人对客观题有误解觉得选择题、判断题就是基础题是“热热身”用的。但在360这种体量的公司技术岗笔试的客观题恰恰是淘汰率最高的环节之一。原因很简单投递量太大了简历筛选之后必须有一轮低成本、高覆盖度的初筛客观题就是干这个用的。它考察的维度很直接你对PHP这门语言的理解有没有形成体系你的知识面是停留在能跑通业务代码还是真的下功夫抠过语言底层和边界情况你的安全意识是挂在嘴上还是刻在处理输入输出的每一个习惯里我做完这套题之后最大的感受是360的客观题不是从《PHP程序员面试题大全》里随机抽的而是有明确的出题倾向基础语法题占大头但不会直接问你“echo和print的区别”而是把变量引用、作用域、运算符优先级这些细节揉进一个具体场景里Web安全相关考点密集出现毕竟公司的安全基因摆在那里数据库和常见框架的题目会结合工程实际不是单纯背概念有一些题目看起来超纲比如让你判断某个伪协议的作用或者某个序列化魔术方法的触发时机其实是故意的——就看你平时有没有主动拓宽过技术视野。1.2 从热搜词反推考点分布大家在搜什么往往就是考什么我当时复习的时候习惯刷技术社区里的热搜词发现一个特别有意思的现象笔试考完那几天“php错误处理”、“php伪协议”、“php序列化”、“PDO访问封装”、“ThinkPHP3.2.3”这些词的热度会明显上升。这其实暴露了大多数人的两个痛点一是复习时根本没把这些点当重点二是考完才发现这些才是拉开分差的地方。结合2018年春招那套题的实际情况我把考点分布整理成了一张表你可以对照着检查自己的盲区考点类别典型考察内容2018春招出现频率复习优先级PHP基础语法变量引用、作用域、数组函数、字符串函数高必须掌握面向对象魔术方法、访问控制、静态成员、接口与抽象类高必须掌握错误与异常error_reporting级别、异常捕获机制、错误抑制中高必须掌握Web安全文件包含、反序列化、SQL注入、XSS高360特色重点准备数据库PDO预处理、SQL语句、事务、索引基础中高必须掌握框架知识ThinkPHP生命周期、路由、I函数过滤中视岗位要求准备网络与LinuxTCP/IP基础、HTTP协议、常用命令、进程中不可忽略算法与逻辑简单数组操作、字符串处理、时间复杂度判断中基础即可这张表里的后四类恰恰是很多“只刷语法题”的候选人翻车的地方。尤其是安全相关考点普通公司可能只考一道SQL注入判断360会从文件包含、伪协议、反序列化、上传校验多个角度反复出题而且干扰项设置得非常细稍微有点模糊记忆就会选错。2. PHP基础考点里的高频陷阱从热搜词反推命题人偏好2.1 运算符优先级与结合性送分题变成送命题的重灾区PHP的基础语法题按理说应该是客观题里最友善的一部分。但我在复盘时发现只要题目涉及运算符优先级错误率就会明显上升。原因不是大家不知道表而是实际做题时很少有人会刻意去背整张优先级表遇到某道题想当然地按“从左到右”算结果就掉坑里了。举个经典例子下面这段代码输出什么$a 0; $b 5; if ($a || $b 10) { echo $b; }很多人一看$a || $b 10下意识会想||两边是逻辑或$b 10是赋值不是比较赋值的优先级比||低所以实际上相当于($a || $b) 10然后直接懵了。正确的理解是PHP中赋值运算符的优先级低于||所以表达式实际上是$a || ($b 10)。由于$a是0假继续判断右侧$b 10这个赋值表达式的值是10真所以整个条件为真$b被赋值为10最终输出10。我当时做题时在草稿纸上写了“赋值优先级在逻辑或之后”这个结论后来回看这类题的核心就是两件事第一背清楚、、、、||、??这组运算符的优先级关系第二养成用括号消除歧义的习惯。考试时看到运算符混杂的表达式先别急着算把优先级层级标出来再动手。还有一个与之相似的陷阱和||的短路求值。比如$a true; $b 0; $result $a || ($b 5); echo $b;因为$a为true短路导致$b 5根本不执行所以$b仍然是0。这个点几乎年年有公司考360当年也出了类似的变体只不过把条件换成了函数调用。2.2 错误处理与异常机制你以为的“报错”其实是一套完整体系“php错误处理”能上热搜说明这个点在笔试里卡住了不少人。PHP的错误处理跟Java、Python很不一样它不是单纯的try-catch一套机制走天下而是分为传统错误级别、异常、错误处理器几个层次。客观题里最常见的是考error_reporting()、display_errors、log_errors这三个配置的关系以及错误抑制符的行为。比如题目会问生产环境下应该怎么配置正确答案思路是display_errors设置为Off避免错误信息直接暴露给用户log_errors设置为On把错误写入日志error_reporting设置为E_ALL尽量暴露所有问题。听起来很简单但干扰项会故意设置成“display_errors设为Off后所有错误都不会被记录”这种说法一看就是错的但很多人选的时候又犹豫了原因就是没把“显示错误”和“记录错误”这两个动作分离清楚。另一个高频点是把抑制符和set_error_handler()结合出题。有个选择题大概是这样的如果自定义了一个错误处理函数那么被修饰的表达式触发的错误还会不会进入这个函数答案是会。只能控制错误是否被显示和记录但不能阻止错误被传送到自定义错误处理函数。这套题当年很多人选错因为大家对的认知停留在“让错误不显示”的层面没有深入理解它和错误处理流程的关系。再往后延伸一点PHP 7之后的Throwable接口、Error和Exception的区别也是偏爱考的点。Error是程序本身的问题比如类型错误、参数错误Exception是程序运行中可以被捕获的异常。在PHP 7之前很多致命错误是没法被catch的PHP 7之后Error类让大部分致命错误也能被捕获了。这个演进过程如果理解了做这类题就不需要死记硬背。2.3 数组与字符串函数零散知识点背后的体系化整理方式数组函数和字符串函数是PHP客观题的题海区域因为函数实在太多了出题人随手就能挑一个考你返回值、参数顺序或者边界行为。我自己复习的时候走过一段弯路一个函数一个函数地背手册背到后面全混了。后来我换了一种方法——按“函数家族”来整理效果立竿见影。举个例子检查数组中是否存在某个key可以用array_key_exists()、isset()、empty()但它们的语义完全不同。isset()在值存在且不为null时返回truearray_key_exists()只要key存在就返回true哪怕值是nullempty()则是值存在、非null、非空字符串、非0等“空值”才返回true。字符串查找strpos()如果找到了目标会返回位置整数找不到会返回false。但位置可能从0开始很多人在判断时直接写if (strpos($str, $needle))当目标恰好位于字符串开头时strpos返回00被当作false于是判断失败。这个坑客观题里出现了不止一次而且选项设计很狡猾会同时出现“返回0”、“返回false”、“返回null”三个看上去都对的说法。把这些函数放在一起对比记忆后你会发现它们的差异点和命题角度其实很集中要么考返回值类型是整数、字符串还是布尔值要么考边界条件位置0、空字符串、null值要么考参数顺序needle和haystack谁在前面。摸清这三个维度之后再遇到没见过的函数也能按这个思路去推断它的行为。3. 安全类客观题360笔试里最有辨识度的部分3.1 PHP伪协议一道题暴露你平时看不看CTF“php伪协议”这个热搜词明显就是从笔试和CTF题里带出来的。伪协议在日常业务开发里用得不多但在文件包含、文件读取相关漏洞里是出镜率极高的概念360作为安全公司在这一块出题几乎是必然的。客观题通常不会让你现场构造利用链而是考你对不同伪协议的理解php://filter常用于读取文件源码配合readconvert.base64-encode可以把文件内容以base64编码输出。这个概念在CTF题目中经常出现也是考察频率最高的一个。php://input可以读取POST原始请求体在有allow_url_include开启的旧配置下可能触发代码执行。data://可以把数据流封装为文件流同样需要allow_url_include配合。file://直接访问本地文件系统属于最基础的文件协议。当年那道题的具体问法我不记得原样了但考察方向是在给定的几个伪协议中哪些可能被用来读取文件内容哪些可能被用来执行代码。选项里会故意混入http://、ftp://这些看起来和网络相关的协议让你犹豫。我的复习建议是把每个伪协议的功能、触发条件、常见配合比如php://filter的base64_encode、需要开启的PHP配置项做成一张对照表。笔试考的是概念面试如果问到安全问题下一步就会追问“你对文件包含漏洞了解多少”这时候如果你能把include $_GET[file]这种代码为什么危险讲清楚比背多少道选择题都有用。3.2 反序列化与对象注入概念题其实考的是触发时机“php序列化中文”这个热搜词看起来很偏门但它背后对应的是序列化与反序列化这个重要考点。序列化就是把对象或者数组转换成一个可存储、可传输的字符串反序列化就是把这个字符串还原成对象或数组。客观题对序列化的考查通常有两条线一条是基础线serialize()和unserialize()的行为、序列化字符串的格式比如O:4:User:1:{...}这样的结构O代表对象4是类名长度User是类名1是属性数量。题目可能会给你一个数组问你序列化后的字符串是什么结构或者反过来给你一段序列化字符串问你还原后是什么类型。另一条是安全线对象注入。核心是unserialize()在还原对象时会触发一些魔术方法比如__wakeup()、__destruct()、__toString()等。如果反序列化的数据是用户可控的攻击者就可以构造恶意的序列化字符串让程序在反序列化时执行危险操作。客观题一般考的是哪个魔术方法会在反序列化时被调用__wakeup的触发顺序是进入unserialize时而__destruct是在对象被销毁时两者时间点完全不同。知道这个区别就能判断题目里描述的执行顺序对不对。我在准备这一块的时候把常见的魔术方法触发时机写在了手册空白处反复看了好几遍__construct对象创建时__destruct对象销毁时__wakeup反序列化恢复对象时__sleep序列化时__toString对象被当作字符串使用时__call调用不存在的方法时需要特别注意的一点是安全线的题目本质上考察的是“攻击者如何控制输入”但对开发工程师来说更应该记住的是防御姿势永远不要对用户提交的数据直接调用unserialize()如果要支持也要加白名单校验、HMAC签名或者用allowed_classes参数限制类白名单。这套防御思路比背考点更有实际价值。3.3 文件操作与上传校验客观题里的场景化安全判断除了伪协议和反序列化360的客观题还特别喜欢把“文件上传”场景化来考给出一段PHP代码让你判断它存在什么安全问题。这种题看起来是在考代码阅读实际上是在考你对文件上传校验链路完整性的理解。经典的一个判断点是只看扩展名白名单够不够不够。攻击者可以结合.htaccess、.user.ini、上传目录下的解析漏洞等方式绕过扩展名校验。所以客观题里如果出现“只要扩展名对就安全”的说法这一项一定是错误项。另一个判断点是move_uploaded_file()函数的参数顺序。正确用法是move_uploaded_file($tmpName, $destPath)目标路径应该由你根据上传类型重新生成而不是直接使用用户传来的文件名。如果代码把$_FILES[file][name]直接拼接到目标路径上就可能出现路径覆盖、目录穿越等问题。还有一类题会考include和include_once、require和require_once的区别。很多人觉得这四个没区别但客观题会精确考“如果文件不存在或引入失败各自会有什么后果”include产生警告脚本继续执行require产生致命错误脚本停止执行带_once后缀的会先检查文件是否已被引入避免重复加载。这个考点单独看很简单但放到文件包含漏洞的语境里就有了新层次——不同的引入方式在错误处理上的差异会影响整个程序的健壮性。4. 数据库与框架相关的客观题工程能力的分水岭4.1 PDO与预处理为什么这一题几乎必考“php数据库pdo访问封装类下载”能成为热搜词说明很多人在笔试前临时抱佛脚想找一个现成的PDO封装拿去背。但客观题不会因为你背了一个封装类就让你过关它考的是你对PDO机制本身的理解。PDO、mysqli、mysql老扩展这三者的区别是历年常客。mysql扩展已在PHP 7中移除不再讨论mysqli是面向MySQL的专用扩展支持面向对象和面向过程两种风格PDO是PHP Data Objects的缩写提供统一的数据库访问接口支持MySQL、PostgreSQL、SQLite等多种数据库。客观题最爱考的点是PDO预处理到底为什么能防SQL注入。这里要理解到位预处理是把SQL模板先发送给数据库进行预编译用户输入只作为参数值传入数据库引擎不会把参数值当作SQL指令解析因此即使参数里包含 OR 11它也只是被当作字符串字面值处理。但是要注意一个坑PDO是否使用预处理取决于你是否真的用了预处理方法。如果只是用PDO::query()拼接字符串那跟普通mysql_query没有任何区别照样存在注入风险。所以看到选项里写“只要用了PDO就绝对安全”可以直接排除。另一类PDO相关题目考的是属性设置比如PDO::ATTR_ERRMODE、PDO::ATTR_DEFAULT_FETCH_MODE、PDO::ATTR_EMULATE_PREPARES。其中ATTR_EMULATE_PREPARES决定了是否使用本地模拟预处理。如果设为falsePDO会使用MySQL原生的预处理如果为true默认在某些驱动下PDO会在本地模拟实际执行时可能把预处理退化成立即拼接。这个点对判断“某段代码是否存在注入”很重要但客观题通常只会让你区分“预处理”和“模拟预处理”的概念能说出差异就够用了。4.2 ThinkPHP 3.2.3与框架生命周期老框架为什么还在考热搜词里出现了“thinkphp3.2.3 { fast simple oop php framework }”这不是乱码是ThinkPHP框架的官方宣传语。360在2018年那会儿的老项目里PHP技术栈用ThinkPHP的比例不低所以笔试出框架题是合理的。框架类客观题一般集中在两个方向第一个方向是框架生命周期。一次HTTP请求进入ThinkPHP后大致会经历入口文件加载框架基础类库 → 注册自动加载 → 解析路由 → 实例化控制器 → 调用操作方法 → 渲染模板输出响应。题目可能会混入“中间件”、“事件机制”等现代框架才有的概念当干扰项如果对ThinkPHP3.2.3的架构不太熟就很容易被带偏。第二个方向是I函数和安全过滤。ThinkPHP3.2.3提供了I()方法来统一获取输入参数并且支持在第二个参数中声明过滤方式。当时的I()方法在默认情况下会进行一些安全过滤但并不是万能的。客观题里会把I()、$_GET直接使用、htmlspecialchars过滤等行为放在一起让你判断各种写法是否安全。我的建议是备考时不用把ThinkPHP源代码全部啃一遍但至少要知道它的请求处理主链路、I函数的实现思路、以及路由解析的基本流程。因为从这些题目能看出公司期望PHP工程师不是只会写个控制器而是遇到框架行为异常时能往下追踪到入口和路由那一层去排查问题。4.3 队列与基础中间件概念考察知识面的广度热搜词里还有“php队列”、“php mqtt”、“php视频会议”这些词。虽然这些不一定直接出现在客观题里但360的笔试确实会在网络和系统基础部分夹杂一些“偏工程架构”的判断题比如消息队列在系统中起到什么作用解耦、削峰、异步处理这三个词是核心Redis实现队列时LPUSHBRPOP组合与LPUSHRPOP组合有什么区别阻塞读与主动读的区别MQTT协议最典型的应用场景是什么物联网消息传输轻量级发布/订阅模型这些题不会深挖但如果你从来没有接触过队列、消息中间件的概念看到题目会完全不知道在说什么。我当时在这个部分能拿分纯粹是因为在项目里用过Redis队列知道基本的命令语义。所以建议那些只做过CRUD的同学在准备笔试时一定要抽出时间把消息队列、缓存、HTTP协议状态码、TCP三次握手这类基础概念过一遍它们不一定每天用但知识面不能让它在选择题里成为盲区。5. 易错题答题思路复盘一道题的完整推理过程5.1 引用与值传递变量机制的底层理解有一类题几乎每场PHP笔试都会出现就是考变量赋值后另一个变量是否会改变。比如$a 1; $b $a; $b 2; echo $a; // 输出什么答案是1因为$b $a在PHP中默认是“写时复制”的值拷贝两者互不影响。但如果改成$a 1; $b $a; $b 2; echo $a; // 输出什么答案是2因为建立了引用关系$b和$a实际上指向同一个变量容器。这类题的推理关键就一句话搞清楚赋值时是“复制”还是“建立引用”。在此基础上360还喜欢把它和函数传参结合function test($x) { $x; } $a 1; test($a); echo $a;答案是2因为函数参数声明为引用传递函数内修改会影响外部变量。如果去掉函数内只是修改了副本外面仍然输出1。看似平淡无奇但干扰项会把“函数参数默认是引用传递”写进选项里诱导你。记住PHP函数参数默认是值传递要用显式声明才是引用传递。5.2 静态变量与作用域闭包和static的组合考法另一个常见陷阱是静态变量。看这段function counter() { static $count 0; $count; return $count; } echo counter() . counter();答案是“12”因为静态变量在函数第一次执行时初始化之后保留上一次结束时的值不会每次进入都置为0。这个知识点本身不难但命题人如果把它和闭包放在一起难度就上来了。比如function makeCounter() { static $count 0; return function() use ($count) { return $count; }; } $c1 makeCounter(); $c1(); $c2 makeCounter(); echo $c2();这里要分清楚静态变量$count是函数级的makeCounter()每次调用都不会重置它而是保留上一次的值闭包通过use ($count)引用它。所以$c1()把$count变成1后$c2()会发现$count仍然是那个静态变量值已经从0变成1再自增后输出2。这类题考核的核心其实是对变量作用域和生命周期的理解静态变量活在函数存续的整个进程里而不是某次调用里。答题时把这个大原则抓住不管题目怎么变都能套进去。5.3 答题节奏与蒙题策略客观题同样需要时间管理2018年春招这套客观题我记得页面上的总题量不小单选、多选、判断混在一起。多选是最坑的少选、错选都不得分所以必须对每一个选项都做出确定性判断才敢勾选。我当时的策略是分三轮第一轮快速做掉有把握的题尤其是判断和单选每条控制在30秒内。遇到需要计算或推演的题先在草稿纸上标记题号不做停留。这一轮的目标是把基础分稳稳拿到手。第二轮回到标记的题集中推演。对拿不准的多选题我的做法是先判断哪些选项肯定是错的把它们排除后剩下的宁可少选也不要选错。因为多选题的计分规则往往是“错选零分、少选得部分分”不确定的选项不勾至少能保住一部分分数。第三轮检查一遍选项是否勾错位尤其是题干问“以下哪项不正确”这类反向提问。我问过几个当年一起笔试的同学都出现过反向题看漏“不”字然后选反的情况。做题时还有一个容易被忽视的细节题目里可能隐藏着“PHP版本限定”。同一段代码在PHP 5和PHP 7里的行为可能不一样比如某些函数从PHP 7开始返回类型变了或者从PHP 8开始参数做了调整。360的笔试虽然不会刻意去考版本边界但遇到和数组、字符串处理相关的题稍微留意一下版本背景可以避免一些误判。如果题目没有明确给版本默认按主流稳定版本2018年就按PHP 7.x来推理。6. 客观题之外的准备从题目反推360对工程师的要求6.1 笔试分数与项目经验的匹配逻辑过了笔试只是起点我在准备这场笔试时踩过一个认知误区以为客观题全对就能进面试。实际上客观题在整条招聘链路里的作用更像是一个“门槛检查”过了门槛之后面试官真正看重的还是项目经验和解决实际问题的能力。2018年春招的流程大概是简历 → 在线笔试 → 面试通常两到三轮技术面HR面。笔试成绩主要决定你有没有资格进面试但面试聊什么基本跟客观题没什么关系——面试官会问你最近做的项目、技术难点、遇到线上故障怎么排查、对某个安全漏洞的理解。所以如果你还在校招阶段我的建议是客观题复习要趁早但不要把大量时间耗在刷题上。客观题覆盖的知识点正好可以作为项目深度思考的引子——比如你在项目里用了PDO那你有没有想过预处理为什么能防注入有没有踩过模拟预处理相关的坑这些问题才是面试时能让你脱颖而出的素材。6.2 从刷题到工程认知安全直觉是360最看重的能力如果要用一个词总结360这套客观题的核心气质我觉得是“安全直觉”。这不是说所有题都和安全有关而是它的出题角度会让你养成一种习惯看到一个输入点先想它会不会被恶意利用看到一段文件操作代码先想路径是否可控看到反序列化先想数据来源是否可信。这种直觉不是背题能背出来的而是靠平时写代码时的自我训练。我后来在项目里养成一个习惯每个对外接口上线前都会拿“如果是攻击者我会怎么打”这个问题过一遍代码。这听起来像安全工程师干的事但对PHP开发工程师来说这种意识恰恰是360这类公司最看重的。所以如果你现在正在准备类似的笔试我给你的建议是不要只刷题把刷到的每个考点都带回项目里检验一遍。看到伪协议相关题目去查查自己的项目里有没有include用户输入的路径看到反序列化相关题目检查一下有没有对用户提交的数据直接调用unserialize()看到PDO相关题目确认一下项目里的SQL是不是都走了预处理。这样复习下来笔试和面试其实是同步准备的。6.3 一个额外的提醒客观题背后的PHP版本意识写到最后我想特别提一下PHP版本意识。2018年的时候PHP 7已经是主流但很多老项目还在跑PHP 5.x。笔试题目如果拿不准可以看看它考的是PHP 5特有行为还是PHP 7新特性。比如PHP 7里foreach不再直接修改内部数组指针、增加了标量类型声明和返回值类型声明、引入了??空合并运算符这些都有可能变成客观题的“隐藏背景”。到了现在PHP 8已经普及新项目里到处都是构造器属性提升、联合类型、match表达式、命名参数这些特性。如果你是现在准备面试除了传统基础知识点外最好也把PHP 8的几个核心语法更新过一遍不然面试官问“你平时用的PHP版本和它有什么明显变化”时会很被动。笔试客观题考的是过去的基础但面试考察的是你现在能不能跟上语言的发展节奏。我把这套题复盘完最大的体会是360的客观题每一道都长着“基础题”的脸但骨子里都在问你——你对这门语言的理解是停留在“能用”还是深入到“懂它为什么会这样”。把这个标准想清楚了你的复习方式会完全不一样。