1. 项目概述:PHP语言服务器到底解决了什么问题
做PHP开发最让人抓狂的时刻,不是业务逻辑理不清,而是代码写顺手了,编辑器突然开始摆烂:补全靠猜、跳转靠搜、错误提示全看缘分。过去大家只能忍,后来PHP方案里慢慢有了语言服务器(Language Server)的路子,其中两个最常被翻牌子的就是Intelephense和PHPActor。前者功能全面、索引能力强,适合中大型项目;后者轻快、省资源,适合快速改小文件或者折腾老旧代码。这篇我把自己实际配置、使用这两个PHP语言服务器的过程整体复盘了一遍,从选型对比到参数调优再到问题排查,能想到的坑都写在里面了。
1.1 传统PHP编辑器为什么跟不上
PHP是一门动态类型语言,没有编译期,也没有像Java或者C#那样严格定义的类文件索引。你写的$user->getName()到底能不能调用,靠的是运行时解释。这种灵活性是PHP能火起来的核心原因之一,但也直接导致了编辑器做静态分析时非常吃力。
早期编辑器对PHP的实现,靠的是正则表达式加简单的词法扫描。它们能把函数名、类名、变量名匹配出来,但一旦涉及继承、接口、魔术方法、依赖注入,正则方案就完全失效了。项目里只要有两个类互相引用,或者用到__call动态转发请求,老式插件的补全和跳转基本就是废的。很多人觉得"PHP项目没法在编辑器里爽快地写代码",根源不在编辑器,而在底层分析手段的落后。
完整IDE产品比如PhpStorm,确实能从一定程度上解决这些问题,因为它内置了完整的PHP解析器、索引器和类型推断引擎。可代价是启动慢、吃内存、需要单独购买授权,而且你一旦习惯了IDE的快捷键和布局,就很难再回到轻量编辑器的节奏里。更多人想要的是:编辑器保持轻量,但语言智能水平向IDE靠拢。语言服务器就是在这个需求下被推上舞台的。
1.2 语言服务器协议(LSP)在PHP里的意义
语言服务器协议,简单理解就是一个统一的"对话标准"。它把"分析和编辑"这两件事彻底分开:编辑器只负责文本编辑、界面展示、快捷键交互;语言智能工作全部交给一个独立的常驻进程来完成。这个进程通过标准协议接收"用户打开了哪个文件""光标移动到了哪里""用户按了补全快捷键"等事件,然后返回补全列表、跳转位置、诊断错误等信息。
这样做最直接的好处是:一套PHP语言服务器可以被无数个编辑器复用。VS Code能用,Neovim能用,Emacs能用,其他支持LSP的编辑器也能用。你不需要在每个编辑器里分别开发一套PHP插件,也不需要在切编辑器的时候重新适应一套补全逻辑。
放到PHP的具体场景里,语言服务器还有一个关键价值:它可以把分析结果常驻内存。传统插件每次补全都要重新扫一遍当前文件,而语言服务器启动时就把整个工作区里与当前项目相关的PHP文件、类、方法、接口的关系建立了索引,后续你无论跳转还是补全,它都在内存里直接查。可以把它想像成一个帮你看代码的顾问,平时一直在翻源码、画关系图,你随时提问它都能立即回答,而不是每次提问都重新翻一遍书。
1.3 这个方案能带来的实际收益
把语言服务器用起来之后,最直观的变化是把编辑器的PHP体验从"文本编辑器级别"拉到了"半IDE级别"。自动补全能从之前只补全你写过的关键词,变成真正的类型感知补全;错误提示能在写出来的瞬间告诉你调用方式不对;重命名一个方法时能联动到所有调用方。团队协作上还有一个容易被忽略的优点:不同成员用不同编辑器或操作系统,但只要工作区配置好了同一个语言服务器,最终的开发体验和智能水平就是一致的,统一排坑的成本会低很多。
性能这件事也变得更加可控。语言服务器可以配置索引范围、缓存策略、内存上限,项目小就用轻量方案,项目大了就上完整索引。相比裸写PHP时要么啥都不会、要么被迫打开一个重型IDE的二选一,方案这个词在这里显得非常贴切:它是一套可调整可组合的工程手段,不是一个坏了只能重启的插件。
2. 工具选型解析:Intelephense与PHPActor该怎么选
2.1 Intelephense:功能全面但需要调教的重量级选手
Intelephense是目前PHP语言服务器里功能最完整、社区使用最广泛的一个,我用它作为主力工具已经很久了。它内部用PHP自身的解析器做静态分析,内置了一套非常完整的PHP运行时stub,这意味着你不需要额外下载PHP文档,它就知道array_map有几个参数、PDO::prepare返回什么类型。
它的能力覆盖了日常开发几乎全部的高频场景:自动补全、方法参数提示、跳转定义、查找引用、重命名、文档符号列表、工作区符号搜索,以及对PHPUnit、PDO、内置扩展的类型支持。更难得的一点是它对各种"不标准但真实存在"的代码有较好的兜底策略。比如代码里用了动态属性、__call转发、或者古老的全局函数,它不一定能完全分析出来,但不会因此直接崩掉整个分析进程。
代价是它的配置项确实多,而且功能越热闹,资源占用就越高。第一次在一个大型PHP工作区里启动时,索引过程能把CPU干到满负载,内存占用也有明显波动。如果你用的是老开发机,需要认真做调优,否则会出现诡异的卡顿。它的授权模式是个人使用免费,团队或商业场景按官方政策购买许可证,买不买不影响试用的完整度,但公司和正式项目都建议按规则来。
2.2 PHPActor:追求轻量和速度的极简路线
PHPActor的定位和Intelephense正好错开。它最大的特点是用PHP实现语言服务器本身,在很多编辑器上配置时不需要额外依赖Node环境,而且整体设计理念就是"能少干活就少干活、能跑得动就是胜利"。
它覆盖的核心能力是日常基础功能:补全、诊断、符号列表、跳转定义、文档大纲。对中小型项目、独立脚本、教学演示或者硬件条件比较差的环境来说,这套能力组合其实刚刚好。配置它的成本也远低于Intelephense,装上之后很少需要花时间看文档逐项调参数,基本上开箱即用。
但反过来说,如果你给它一个几千个文件、类继承关系特别复杂的业务系统,它能提供的智能水平会明显感觉到上限:复杂泛型推断、深度跨文件引用、高级重构操作,它做得就比较基础了。这不是缺陷,而是取舍。就好比通勤代步车不需要塞一台越野发动机,场景匹配比"听起来很强"更重要。
2.3 两个工具的横向对比与选型思路
下面这个表是我在实际使用中总结出来的对比,整理成了适合快速决策的格式:
| 对比维度 | Intelephense | PHPActor |
|---|---|---|
| 目标定位 | 对标IDE的完整静态分析 | 轻量快速的日常辅助 |
| 自动补全 | 类型感知强,支持泛型与PHPDoc | 基础补全,够用不惊艳 |
| 诊断能力 | 多项开关可细粒度控制 | 基础诊断,配置项少 |
| 跳转与引用 | 跨文件索引完整,结果准 | 中小项目够用,大项目有限 |
| 重构能力 | 支持重命名、组织导入等 | 基本不做复杂重构 |
| 配置复杂度 | 较高,需要调优 | 极低,开箱即用 |
| 资源占用 | 首次索引耗CPU,内存较高 | 轻量,适合老机器 |
| 适合场景 | 中大型业务项目、团队协作 | 学习、脚本、资源受限场景 |
选型思路我个人建议看三条线。第一条线是项目规模:文件过千、依赖复杂,直接Intelephense;临时脚本、几十个文件的小工具,PHPActor完全可以。第二条线是机器配置:手头是主力开发机或者内存16G以上,Intelephense的体验优势能完全释放;如果是低配笔记本或远程小服务器上开发,那轻量方案反而更实用。第三条线是协作需求:团队统一用同一套工作区规范,Intelephense的配置可以沉淀成项目级设置文件传给仓库里的所有人,这比每个人靠记忆手动装插件要靠谱得多。
注意:选型不是越多越好,同一个编辑器里建议只启用一个PHP语言服务器,两个同时启用会导致功能互相竞争、诊断结果重复甚至冲突,具体在后面问题排查部分我会详细讲。
3. 核心功能拆解:补全、诊断、跳转和重构的实际表现
3.1 自动补全:从"能用"到"好用"的距离
补全这件事,表面上看是"敲几个字母出一个列表",但背后完全是另一回事。传统方案只会匹配你已经写过的文本片段,而基于语言服务器的补全需要先分析当前文件里的类型环境,才知道该显示什么内容。你写$this->,它能列出当前类的全部属性和方法;你写$user->get,它能根据$user的PHPDoc类型,跨文件推断出get开头的方法。
想达到这个效果,前提是你得把代码的"输入信息"喂给分析器。以PHP为例,最重要的输入就是PHPDoc注解。很多人觉得PHPDoc是写给后人看的注释,懒得写,但从语言服务器的角度看,@param和@return就是类型推导的最关键证据。我在实际项目里见过一个非常典型的情况:两个方法实现完全相同的逻辑,一个有完整的PHPDoc,一个没有,在Intelephense里补全体验天差地别。
如果你接手的是老项目,代码里大量使用动态调用,比如__call转发请求,那无论哪个语言服务器都很难从静态层面推出来。这里有一个实在的解决思路:针对这些动态类的PHP文档注释里补充@method标签,把可能动态调用的方法名和签名提前声明清楚。查过文档的读者应该知道,这个方式等于告诉分析器"这些方法虽然写出来不存在,但运行时是有的",补全效果能立刻提上来。
3.2 诊断分析:让错误在写代码时就被抓出来
诊断功能是语言服务器价值最外显的一块。Intelephense默认开启了对未定义类型、未定义方法、未定义属性、未定义常量、未定义变量的检查,这意味着很多运行时才会爆出来的错误,在保存文件甚至输入过程中就会被红波浪线标出来。这个能力的杀伤力非常大,尤其对变量名拼错的情况,经常是在浏览器里调半天才发现的低级错误,现在写出来的瞬间就已经暴露了。
诊断功能不是只能全部开或全部关,它提供了细粒度的开关。比如老项目里大量使用动态属性,那undefinedProperties就会疯狂误报,这时候单独关掉这一项,其他诊断能力完全不受影响。我见过有人因为误报太多干脆关闭整个诊断功能,这种做法其实因噎废食:你应该做的是关闭那一个不匹配当前代码风格的选项,而不是把整块能力扔了。
诊断还和PHP版本设置直接相关。Intelephense支持通过intelephense.environment.phpVersion指定当前项目的PHP版本。如果项目跑在PHP 7.2,但你把这个参数留空,它默认按最新版解析,那就会把旧代码里某些已废弃的写法当成错误标出来。反过来,如果你的代码用了PHP 8.2的新语法,而环境配置停在7.4,那它分析出来的结果一样是歪的。
3.3 跳转与导航:跨文件的索引思维
跳转到定义看起来是个小功能,但它依赖的能力其实是整个项目级索引。Intelephense启动后会对工作区里的PHP文件建立文件列表,分析每个文件的命名空间、类声明、函数声明,再汇总出符号表。你在一个文件里按下跳转快捷键,它能从符号表查到目标类或方法所在文件的精确行号,直接把你带过去。
与之配套的还有查找引用、文档符号、工作区符号搜索。文档符号解决的是"当前文件里有哪些类和方法",工作区符号解决的是"整个项目里有哪些类和方法"。配合起来用,哪怕你完全不记得某段代码在哪个文件里,只记得类名大概长什么样,也能两秒内定位到目标。
实际使用上,跳转体验受两个因素影响:一是索引没有覆盖目标文件,二是索引没有刷新。前者通常出现在代码依赖了没有被纳入工作区的目录,后者通常出现在刚用Git换了分支、文件被批量改动之后。定位这种问题最直接的手段是看语言服务器日志,它会告诉你索引了哪些目录、跳过了哪些路径,比瞎猜快得多。
3.4 重构与代码操作:语言服务器带来的额外红利
很多人对语言服务器的认知停留在补全和跳转,其实重构能力才是真正提升效率的隐藏福利。Intelephense支持的重命名是真正的跨文件重命名,在一个接口的方法名上按快捷键,所有实现类和调用方的引用会被一起更新。这种能力如果靠手动查找替换来做,看漏一个引用就会埋下运行时炸弹。
除了重命名,它还支持一些代码操作,比如自动导入类、生成PHPDoc注释、从构造函数属性初始化排序等等。最常用的自动导入类是这样一个体验:你在代码里写$client = new HttpClient();,按下快捷修复键,它自动补上对应的use语句。这个操作听起来简单,但在类名和文件名不一致的项目里,手动找路径就够烦的,自动完成能够让写样板代码的过程变得平滑很多。
这些操作并不像IDE那样铺满菜单,而是藏在快捷键和右键菜单里面。刚上手的人常常忽略它们,但把常用快捷键练熟之后,你的日常编辑节奏会完全不一样。我个人在项目里用得最频繁的三个操作是:重命名符号、自动导入类、快速查看定义。
4. 实操配置:把Intelephense调成适合你的工作流
4.1 环境准备与安装
使用Intelephense前的第一个条件,是机器上要有可用的PHP CLI环境。你可以在终端执行php -v确认有没有PHP可执行程序,如果没有,需要先安装对应操作系统的PHP命令行版本。这一步不是一个可选步骤,因为Intelephense的解析器底层要调用PHP来跑,你没有PHP环境,装上插件也只能看到一个转圈圈的加载状态。
以主流编辑器为例,安装Intelephense的方式基本都是在插件市场里搜名字然后直接安装。装好之后最关键的配置是intelephense.php.executablePath,它指定语言服务器需要的PHP可执行文件路径。在macOS或Linux环境里路径一般是/usr/local/bin/php,Windows环境则是类似C:\php\php.exe的绝对路径。有人装了扩展就卡在"永远加载中",排查了一圈才发现是这个路径没配对。
我做环境准备时会一并检查两个细节:一是PHP版本,二是常用的扩展模块是否启用,比如mbstring、openssl。语言服务器在某些功能上会依赖PHP扩展来解析和处理文件,缺了扩展虽然不至于完全不能用,但可能出现一些莫名其妙的边界错误。环境问题越早确认,后面排错的空间就越大。
4.2 核心配置逐项说明
下面这份是我在真实项目里长期使用的配置文件,各项基本都有注释,可以直接作为参考起点:
{ "intelephense.php.executablePath": "/usr/local/bin/php", "intelephense.environment.phpVersion": "8.2", "intelephense.environment.includePaths": [ "vendor", "includes" ], "intelephense.environment.documentRoot": "public", "intelephense.files.exclude": [ "**/cache/**", "**/storage/**", "**/node_modules/**" ], "intelephense.indexedFiles": 50000, "intelephense.diagnostics.enable": true, "intelephense.diagnostics.undefinedTypes": true, "intelephense.diagnostics.undefinedMethods": true, "intelephense.diagnostics.undefinedProperties": true, "intelephense.completion.triggerParameterHints": true }intelephense.environment.phpVersion指定项目语义解析用的PHP版本,一般和线上运行环境保持一致即可。includePaths用于声明需要额外包含到索引目录里的路径,最常见的就是框架的vendor目录。files.exclude用来排除不需要索引的下脚料目录,例如日志、缓存、构建产物。indexedFiles控制索引文件的规模上限,防止无限吃内存。
我把completion.triggerParameterHints默认开启,这个功能会在补全方法时同时显示参数名称和类型,对于不记得参数顺序的情况很有帮助。它可用的前提是代码里有清晰的PHPDoc或者PHP原生签名,所以前面说的写注释问题,在实际编码体验里真的会回来找你的。
4.3 vendor与依赖路径的处理
现代PHP项目基本都依赖Composer管理第三方包,绝大多数类和函数都躺在vendor目录里。也就是说,你补全时真正需要分析的源码,很大一部分在依赖目录里,而不在你的业务代码目录里。如果Intelephense没有把这些依赖纳入索引,那你就会看到一个诡异的状况:自己的代码能补全,但一调用第三方库就全部变成未知。
处理方式有两种。第一种是你直接用编辑器打开项目根目录,默认情况下它会把整个工作区,包括vendor子目录一并纳入扫描。这种方式省事,但会在索引全部依赖时消耗大量时间和内存。第二种方式是显式配置includePaths,只把你项目实际引用的依赖目录加进去,同时通过files.exclude把不需要扫描的第三方调试文件、文档目录排除掉。这种方式可控性更好,大型项目更推荐。
注意:很多人为了让补全"绝对完整",把整个硬盘里的PHP目录都塞进includePaths,结果索引慢到怀疑人生。正确的思路是只索引代码实际运行需要的那部分,而不是贪大求全。
4.4 PHPActor的快速配置与适用场景
如果你决定在资源受限或小型项目场景里用PHPActor,配置过程会轻松得多。安装扩展后再确认PHP可执行文件路径,然后把补全、诊断、跳转这些能力默认开着就行,几乎没有需要深调的项。
它真正出彩的场景,我在实际使用中遇到的是一个极端的例子:在一台配置很老、只有2G内存的备用开发机上调试一套遗留脚本,当时我用Intelephense打开后先是卡了将近十分钟索引,然后内存报警直接熄火。换成PHPActor之后,虽然智能程度打了折扣,但至少能正常写代码了。这个经历提醒我,工具没有绝对的优,只有跟环境匹不匹配。
另外,如果你做一些临时性的小工具、写教学示例、或者需要频繁切换不同PHP版本的笔记本环境,PHPActor的轻量和低配置成本也很有吸引力。它不是用来替代Intelephense的,而是用来在特定场景下兜底的。
5. 性能调优与内存管理
5.1 索引策略:别让全部文件都进内存
语言服务器吃内存的核心原因,就是它要把分析过的文件信息都留在内存里建索引。文件越大、目录越多,索引自然越大。如果你不停给它喂文件,内存最终会被吃满,然后开始走交换分区,性能直线下降。
控制索引范围最直接的手段是indexedFiles。这个参数定义了索引文件数量的上限,值越小占内存越少,但能补全和跳转的范围也随之变小。我的经验是,业务代码文件数一般不会多到夸张,真正常驻内存的大头是vendor里的依赖文件。可以默认设一个较大值,但至少要让它在当前项目实际文件数和内存余量之间找到平衡。
files.exclude同样是重点。很多项目根目录下会有日志目录、缓存目录、生成目录、node_modules目录,这些东西对PHP分析毫无价值,却会占据宝贵的索引资源。把这些目录提前排除,索引速度能立竿见影地提升,内存占用量也会肉眼可见地下降。
5.2 常见卡顿来源与解决思路
我遇到过的最奇怪的卡顿,来自一个PHPDoc长得惊人的方法。那个方法本身的逻辑只有十几行,但注释里罗列了两百多个参数说明和示例,最终导致每次补全请求都需要对这个文件做一次完整解析,编辑器的响应时间从毫秒级直接跳到秒级。这种问题的处理方式很朴素:检查文件是否过度膨胀,把注释冗余的部分删掉或拆分。
另一个常见卡顿是文件监听。编辑器默认监听工作区文件变化并实时通知语言服务器刷新索引,当某个目录下文件数量极其庞大时,监听事件会像洪水一样灌进服务器。这个现象在把vendor整个纳入工作区时特别明显。解决办法是同时配置编辑器的监听排除规则,把不需要监听的目录排除在外。
如果你用的是老版本Intelephense,建议先检查一下是不是很久没更新了。语言服务器的索引算法和PHP解析器版本是持续改进的,很多性能问题在新版本里都已经修过了。定期升级依赖本身就是一种省力的性能调优方案。
5.3 Monorepo与多根工作区场景的特殊处理
如果你在一个Monorepo里维护多个PHP服务,每个服务有自己的vendor目录、共享的公共包和独立的配置,那工作区设置就不能一刀切了。直接把整个Monorepo根目录打开,让语言服务器去扫全部内容,不仅是慢,还会出现依赖路径互相打架的情况。
我的处理方式是给每个服务目录做独立配置,在项目级设置文件里分别声明各自的includePaths和exclude规则。如果多个子项目需要共享某个公共包,我会把公共包装成独立的依赖包,让子项目通过Composer按常规方式引用,而不是直接把公共目录暴露在多个includePaths里。这样既保持了索引的清晰边界,也避免了两个子项目同时往索引里塞相同类定义时出现的跳转混乱。
提示:Monorepo里若出现"跳转到定义时跑到了另一个服务的同级类"这种诡异情况,几乎可以断定是多个工作区根互相污染了索引,按我这里的方式隔离后很快就能解决。
6. 常见问题与排查技巧实录
6.1 补全和诊断集体失灵
装了扩展之后什么提示都不出,这是提问频率最高的一个问题。排查链路应该按照"环境是否满足、进程是否启动、索引是否建完"的顺序来走,不要一上来就卸载重装。
首先确认PHP CLI能否正常运行,然后在编辑器的输出面板里找到语言服务器日志,看有没有实际启动记录。如果日志显示找不到PHP路径,去修改executablePath;如果日志报错里带着权限或网络字样,很可能是下载运行时stub时被网络拦截了,需要处理网络连通性或者手动把stub文件放置到缓存目录。日志里能看到索引了多少文件,如果一直卡在0,那就要检查工作区根目录是否被正确识别为PHP项目。
6.2 跳转到定义后"定位不准确"
这个问题的形态很多:有时跳到的是方法名而不是方法体,有时跳到了interface而不是实现类,有时跳到了几乎相同的另一个同名类。本质原因通常是索引状态和当前磁盘内容不一致,文件被批量修改、分支切换、或者外部代码生成工具改动了文件之后,语言服务器的缓存还停留在旧状态。
遇到跳转不准时,先试着手动触发一次重新索引。具体操作是执行语言服务器提供的"重新索引工作区"命令,或者干脆重启一次编辑器的窗口。如果还不行,就去缓存目录里把Intelephense的索引缓存清掉再重启。这一步听起来很暴力,但在大多数场景下是能见效的最后一击。
6.3 误报与高频报错的抑制策略
误报到一定量级会让人想关闭所有诊断,但正确的策略是区分误报类型。动态属性引发的undefinedProperties误报、魔术方法引起的undefinedMethods误报,都可以用单独开关关闭。这类开关的命名都很直观,直接在诊断配置里找对应项就行。
还有一类误报来自静态分析器无法理解自定义全局函数或者被动态include进来的文件。如果你确实知道这些函数在试运行环境中是存在的,可以给它们补一份轻量stub文件,在文件里用PHPDoc声明这些函数的签名,再把stub目录加入includePaths。这本质上是"教"语言服务器理解项目的私有个性化契约,比逐个忽略错误提示要可靠得多。
6.4 Intelephense与PHPActor同时在编辑器里打架
同时安装两个PHP语言服务器扩展,编译器层面就可能出现竞争关系:同一个操作会同时发两份文本编辑请求,导致你明明选择了Intelephense的补全结果,却被PHPActor的结果覆盖掉,或者诊断面板里同样的错误出现两遍、且报错位置细节还不一样。这种场景在真实使用中并不罕见,不少人的确会为了"集两家之长"同时装两个。
解决方案很简单:按工作区分别禁用其中一个扩展。比如编辑器的命令面板里允许你为当前工作区禁用扩展,你完全可以在这个项目里只开Intelephense、在另一个项目里只开PHPActor。用工作区分工而不是在同一工作区里硬凑两个服务器,这是最干净的处理方式。
我把常见问题和解决思路整理成一个速查表,方便后面遇到直接对照:
| 现象 | 可能原因 | 解决动作 |
|---|---|---|
| 完全没有补全和诊断 | PHP路径未配置或进程未启动 | 检查CLI环境、查看日志、确认exe路径 |
| 补全结果带着奇怪的老版本风格 | PHP版本设置偏低 | 设置environment.phpVersion为实际运行版本 |
| 第三方依赖补全为空白 | vendor目录未纳入索引 | 配置includePaths或直接打开项目根目录 |
| 跳转定位到了旧版本代码 | 索引未刷新 | 手动重新索引或清理缓存 |
| 诊断误报大量动态属性 | 静态分析与动态特性冲突 | 关闭对应诊断项或补充stub声明 |
| 打开项目后内存暴涨 | 索引范围过大 | 调整indexedFiles和files.exclude |
| 两个服务器结果互相干扰 | 同时启用了多个语言服务器 | 在当前工作区禁用其中一个 |
7. 我这段时间用下来的最终组合与体会
折腾完Intelephense和PHPActor这两个PHP语言服务器方案之后,我现在的日常使用习惯很固定:主力开发机上,公司业务项目全部用Intelephense,配置沉淀在项目级设置文件里,成员切新环境时直接拉仓库配置即可;自己的小工具和个人博客,大部分时间直接上PHPActor,因为不需要等完整索引,打开就能开始写。
实际用下来最大的感悟是,语言服务器这个东西不是装好就一劳永逸的,它需要根据项目类型、机器配置、团队协作习惯慢慢磨合。尤其是Intelephense,它给你的每一项能力背后基本都对应着一个可调参数,多花点时间把配置从默认改成"适合自己项目的样子",收益远比无脑升级插件版本要大。
踩过几次坑之后,我现在做PHP开发时养成了一个习惯:每逢新项目,先花五分钟配好PHP版本、includePaths和缓存排除三项,再开始写业务代码。这个操作成本极低,但后面能省下的时间回报可观。如果你现在正被编辑器补全不聪明、跳转乱跑、报错满天飞这些事折磨,别急着怪代码,先把语言服务器方案这层地基打好,体验可能直接上一个台阶。