l1n6yun's Blog

记录学习的技能和遇到的问题

做 PHP 开发,composer installcomposer require 基本是日常,但 Composer 的钩子脚本,估计不少同学都没怎么用过。

最近想弄一个项目模板,让其他人可以通过 composer create-project 一键安装,安装完自动把 .env.example 复制成 .env、生成密钥、提示下一步操作。折腾了一番,踩了不少坑,今天把经验整理出来,希望能帮到有同样需求的同学。

先把坑填上:type 必须是 project

这个坑我踩得很惨——模板写好了,composer create-project 却死活装不了。

问题出在 composer.jsontype 字段。想用 create-project 安装,这个字段必须是 project,填 library 的话只能 composer require

建模板其实很简单:

1
2
mkdir my-project-template && cd my-project-template
composer init

composer init 的时候注意两点:一是 Package name 要用「作者名/包名」的格式,比如 l1n6yun/my-project-template;二是 Project typeproject

生成的 composer.json 最小结构:

1
2
3
4
5
6
7
{
"name": "l1n6yun/my-project-template",
"type": "project",
"require": {
"php": ">=7.4"
}
}

然后在模板里放好 .env.exampleindex.php 这些基础文件,一个能被 create-project 识别的模板就有了。

三个钩子的区别,搞清楚就够用了

Composer 钩子有好几个,但做项目模板主要用这三个:post-root-package-installpost-autoload-dumppost-create-project-cmd

post-root-package-install:模板刚下载完

用户执行 composer create-project,Composer 把你的模板下载下来,还没开始装依赖(此时 vendor 目录还不存在),这个钩子就触发了。

最适合干的事:复制 .env.example.env

为什么?因为这时候模板文件刚到位,.env 还不存在,是复制的最佳时机,而且不用依赖任何包,执行最快。Laravel 官方也是这么干的。

1
2
3
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
]

用 PHP 的 copy() 函数,Windows、Linux、Mac 通用,不用管系统命令的差异。

post-autoload-dump:vendor/autoload.php 生成后

触发时机:composer installcomposer updatecomposer dump-autoload,以及 create-project 安装依赖完成后。

简单说,依赖装好了,需要用到 vendor 里的类了,这个钩子就派上用场了。

常见用途:框架的插件自动发现、生成缓存、初始化需要加载类的操作。

1
2
3
"post-autoload-dump": [
"@php artisan package:discover --ansi"
]

注意:别用这个钩子复制 .env,这时候依赖都装完了,再复制环境文件可能会出问题。

post-create-project-cmd:全部搞定,最后一步

create-project 流程全部结束后触发,依赖装好了、自动加载器也生成了,项目完全就绪。

最适合做的事:给用户友好提示、执行最终初始化操作。

1
2
3
4
"post-create-project-cmd": [
"@php artisan key:generate --ansi",
"echo 项目安装成功!执行 php artisan serve 启动服务~"
]

一套完整配置,直接拿去用

把三个钩子组合起来,就是一套完整的脚本配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"name": "l1n6yun/my-project-template",
"type": "project",
"require": {
"php": ">=7.4"
},
"scripts": {
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-autoload-dump": [
"@php artisan package:discover --ansi"
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi",
"echo 项目安装成功!"
]
}
}

最后说几个注意点

  1. 执行顺序post-root-package-installpost-autoload-dumppost-create-project-cmd,顺序不能乱,否则依赖找不到、文件生成失败都会出现。

  2. 复制 .env:用 post-root-package-install,这是官方推荐的做法。

  3. @php 是什么:Composer 的内置命令,表示用当前项目的 PHP 解释器,避免系统 PHP 版本和项目要求不一致。

  4. 本地测试:模板建好后,执行 composer create-project ./my-project-template test-project,看 .env 是否自动生成、提示信息是否正常显示。

  5. 包还没发布怎么办:如果模板还在开发阶段,没有发布到 Packagist,可以用 --repository-url 参数指定仓库地址。比如你的模板托管在 GitHub,可以这样安装:

    1
    composer create-project l1n6yun/my-project-template my-app --repository-url=https://github.com/l1n6yun/my-project-template.git

这样就能直接从 Git 仓库拉取安装,不用先发布包。本地测试也可以用这个方式,把地址换成本地路径就行。

Composer 的钩子其实不难理解,关键是搞清楚每个钩子的触发时机,按需分配操作就行。掌握这三个,项目模板的自动化初始化就搞定了,用户的安装体验也能上一个台阶。

有问题欢迎评论区交流~

有时候写 PHP 项目,需要在服务端主动发起 POST 请求——比如调用第三方接口、模拟表单提交、做个简单的采集之类的。这种需求还挺常见的,我这里整理了三种常用方式,备忘一下。

阅读全文 »

最近在搞一个 Vue3 + Vite 的项目,想着给项目加上 ESLint,结果发现 ESLint 现在推荐用新的 flat config 格式了,跟之前那种 .eslintrc.js 的写法完全不一样。折腾了一阵子终于搞定,记录一下配置过程,希望能帮到同样遇到这个问题的小伙伴。

安装依赖

首先当然是装 ESLint 和相关插件啦:

1
npm install -D eslint @eslint/js eslint-plugin-vue

这里简单说一下装的几个包都是干啥的:

  • eslint - ESLint 核心,不用说
  • eslint/js - JavaScript 官方推荐的规则集
  • eslint-plugin-vue - Vue 官方的 ESLint 插件,专门检查 Vue 组件的

写配置文件

ESLint 现在推荐使用 flat config 格式,配置文件名是 eslint.config.js,写法跟以前差别挺大的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import js from '@eslint/js'
import pluginVue from 'eslint-plugin-vue'

export default [
{
name: 'ignores',
ignores: [
'dist/**',
'node_modules/**',
]
},
js.configs.recommended,
...pluginVue.configs['flat/recommended'],
{
languageOptions: {
globals: {
localStorage: 'readonly',
sessionStorage: 'readonly',
window: 'readonly',
document: 'readonly',
console: 'readonly',
setTimeout: 'readonly',
clearTimeout: 'readonly',
setInterval: 'readonly',
clearInterval: 'readonly',
fetch: 'readonly',
URL: 'readonly',
process: 'readonly'
}
},
rules: {
'vue/multi-word-component-names': 'off',
'vue/no-v-html': 'warn',
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'no-console': 'off',
'no-debugger': 'warn'
}
}
]

这里有几个坑说一下:

第一个坑:一定要在配置里声明浏览器全局变量!不然 ESLint 会报 localStorage is not defined 之类的错误。上面配置里的 globals 就是干这个的。

第二个坑ignores 要放在第一个配置对象里单独写,不能跟其他配置混在一起。

自定义规则说明

  • vue/multi-word-component-names: 'off' - 这个规则要求组件名必须是多单词的,我习惯用单词组件名,干脆关掉了
  • vue/no-v-html: 'warn' - 用 v-html 有 XSS 风险,改成 warn 提醒自己注意
  • no-unused-vars - 未使用变量改成警告,argsIgnorePattern: '^_' 表示以 _ 开头的参数可以忽略(有时候回调函数的参数不用但又必须写在前面)

配置 npm 脚本

package.json 里加上:

1
2
3
4
5
6
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix"
}
}

这样就可以用 npm run lint 检查代码,用 npm run lint:fix 自动修复能修的问题。

集成到 Vite

光有命令行检查还不够,开发的时候能实时看到问题更方便。装个 vite-plugin-eslint:

1
npm install -D vite-plugin-eslint

然后在 vite.config.js 里加上:

1
2
3
4
5
6
7
8
import eslint from 'vite-plugin-eslint'

export default defineConfig({
plugins: [
vue(),
eslint(),
],
})

这样 Vite 开发服务器启动后,代码有问题会直接在页面上弹出来,再也不用手动跑 lint 命令了。

一些常见问题

中文全角空格报错

有时候复制代码会带上中文全角空格,ESLint 会报 no-irregular-whitespace。这个一般 IDE 能看出来,注意一下就行。

未使用的导入

no-unused-vars 这个规则经常会报,比如:

1
2
3
4
5
// 报错:nextTick 未使用
import { nextTick, ref } from 'vue'

// 改成这样
import { ref } from 'vue'

如果有些变量确实暂时不用但想留着,可以在变量名前加个下划线 _,因为上面配置了 argsIgnorePattern: '^_'

小结

ESLint 配置这东西,一开始看着挺麻烦的,配好之后真的能避免很多低级错误。尤其是多人协作的项目,统一代码风格太重要了。flat config 虽然写法变了,但配置逻辑其实更清晰了,习惯了就好。

如果这篇对你有帮助,欢迎留言交流~

最近在写项目的时候用到了 Element Plus 的下拉菜单组件 el-dropdown,本来挺好用的,但是每次鼠标悬浮或者点击的时候,总会冒出来一个黑色的边框,看着特别别扭。

这个边框其实是浏览器自带的焦点样式,就是那种 tab 切换时候会显示的轮廓线。虽然从可访问性的角度来说这是个好东西,但有时候跟设计稿对不上,还是得把它干掉。

怎么解决呢?

其实很简单,就是用 CSS 把 outline 去掉就行。但是因为 el-dropdown 内部的样式是 scoped 的,所以得用样式穿透才能生效。

Vue 3 的写法

1
2
3
:deep(.el-tooltip__trigger:focus) {
outline: none;
}

这里要注意一下,el-dropdown 内部触发下拉的元素有个 el-tooltip__trigger 类,我们就是要把这个类上的焦点样式去掉。

Vue 2 的写法

如果你还在用 Vue 2 的话,写法稍微有点不一样:

1
2
3
::v-deep .el-tooltip__trigger:focus-visible {
outline: unset;
}

一点小知识

顺便说一下 outlineborder 的区别吧,刚开始学 CSS 的时候老搞混:

  • outline 不占空间,画在元素外面,不影响布局
  • border 占空间,会影响元素的尺寸

所以这个焦点边框才会”凭空出现”,不会把页面撑开或者挤跑其他元素。

完整代码

放一段完整的代码,方便直接复制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<el-dropdown>
<span class="dropdown-link">
下拉菜单
<el-icon><arrow-down /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>选项一</el-dropdown-item>
<el-dropdown-item>选项二</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>

<style scoped>
:deep(.el-tooltip__trigger:focus) {
outline: none;
}
</style>

最后

这个小问题当时还是让我找了一会,因为一开始不知道要穿透的类名是 el-tooltip__trigger,一直在 el-dropdown 那里瞎折腾。希望能帮到同样遇到这个问题的小伙伴~

平时写代码有没有遇到过这种情况:刚提交完,发现用错账号了——公司项目用了个人邮箱,或者反过来。我就干过这事,提交完了才看到 git log 里邮箱是自己的 Gmail,尴尬得很。

Git 提交记录里的作者信息,一旦提交就写进历史了,改起来确实麻烦。但也不是不能改,今天就把几种场景的方法说清楚,遇到问题直接照抄命令就行。

先说几句注意事项,省得踩坑:

  • 改提交记录会生成新的 commit hash,相当于重写历史
  • 如果已经 push 到远程了,改完得强制推送,会覆盖远程历史
  • 团队协作的话,改之前一定要通知大家,让人家先备份一下

先看看当前提交是啥情况

改之前先确认一下现在的提交信息:

1
2
3
4
5
6
7
# 看最近5条提交的作者、邮箱
git log --pretty=format:"%h %an <%ae> %s" -5

# 看当前仓库的 git 配置
git config --list --local | grep user
# 看全局配置
git config --list --global | grep user

这样能快速定位要改的是哪条提交。

场景一:刚提交完,发现用错账号了(还没 push)

这是最常见的情况,刚 commit 完,还没 push,发现作者信息错了。这种情况最简单,一条命令搞定。

方法一:直接指定新作者

不用改配置,直接改这次提交:

1
2
# 换成你的名字和邮箱
git commit --amend --author="张三 <zhangsan@company.com>" --no-edit

--no-edit 的意思是不改提交信息,只改作者。

方法二:先改配置再同步

如果你要长期用新账号,可以先把配置改了:

1
2
3
4
5
6
7
8
9
10
# 只对当前仓库生效(推荐,不影响其他项目)
git config user.name "张三"
git config user.email "zhangsan@company.com"

# 如果所有项目都要用这个账号,加 --global
# git config --global user.name "张三"
# git config --global user.email "zhangsan@company.com"

# 然后把最近一次提交的作者更新一下
git commit --amend --reset-author --no-edit

改完再看 git log,作者信息已经变了。

场景二:之前某次提交写错了(还没 push)

错的不一定是最近一次,可能是之前某一条。这种情况要用交互式变基,精准定位那条提交。

假设要改最近 3 条提交里的某一条:

第一步:启动变基

1
2
# 查看最近3条提交
git rebase -i HEAD~3

第二步:标记要改的提交

执行后会弹出编辑器(默认 vim),显示类似这样的内容:

1
2
3
pick abc1234 第一次提交
pick def5678 第二次提交
pick ghi9012 第三次提交

每条前面是 pick,表示保留这条提交。把要改的那条前面的 pick 改成 edit(或者简写 e),然后保存退出(vim 里按 Esc,输入 :wq 回车)。

第三步:修改作者

Git 会停在你标记的那条提交上,提示你可以修改了:

1
git commit --amend --author="张三 <zhangsan@company.com>" --no-edit

第四步:继续变基

1
git rebase --continue

如果要改多条,会一条条停让你改,重复步骤三四就行。

如果变基过程中冲突了,先解决冲突,然后 git add .,再 git rebase --continue

场景三:批量改,仓库里好多提交都要换人

如果是离职员工的提交要统一改掉,或者换企业邮箱后要批量更新,一条条改太累了。这种情况用 git filter-branch 批量处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 把旧邮箱的所有提交都改成新的作者信息
git filter-branch --env-filter '
OLD_EMAIL="old@example.com"
CORRECT_NAME="张三"
CORRECT_EMAIL="zhangsan@company.com"

# 改提交者
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]; then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi

# 改作者
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]; then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' -f --tag-name-filter cat -- --branches --tags

参数说明:

  • --env-filter:通过环境变量过滤修改
  • -f:强制覆盖之前的备份
  • --tag-name-filter cat:同步更新标签
  • --branches --tags:处理所有分支和标签

更快的工具:git filter-repo

git filter-branch 处理大仓库比较慢,官方推荐用 git filter-repo

1
2
3
4
5
6
7
8
9
10
11
12
# 先安装
pip install git-filter-repo

# 批量替换
git filter-repo --commit-callback '
if commit.author_email == b"old@example.com":
commit.author_name = b"张三"
commit.author_email = b"zhangsan@company.com"
if commit.committer_email == b"old@example.com":
commit.committer_name = b"张三"
commit.committer_email = b"zhangsan@company.com"
'

已经 push 了怎么办?

前面说的都是没 push 的情况。如果已经 push 到远程了,改完本地历史后必须强制推送:

1
2
3
4
5
# 推单个分支
git push origin main --force

# 推所有分支(慎用)
git push origin --force --all

强制推送会覆盖远程历史,团队协作的话一定要提前通知,让人家先 git pull --rebase 同步一下。

验证一下改没改对

改完确认一下:

1
2
3
4
5
6
# 看最近几条提交
git log --pretty=format:"%h %an <%ae> %s" -5

# 对比本地和远程
git fetch origin
git log --oneline HEAD..origin/main

没输出就说明同步好了。

几个常见问题

Q: vim 编辑器不会用怎么办?

vim 操作:按 i 进入编辑模式,改完按 Esc,输入 :wq 回车保存退出。

想换成记事本的话:git config --global core.editor notepad

Q: 强制推送后同事拉代码报错?

让同事执行:git pull --rebase origin main,有冲突解决冲突,然后 git add .,再 git rebase --continue

Q: 改完 commit hash 变了?

正常的,hash 是根据提交内容、作者、时间算出来的,改了作者 hash 肯定变。不影响功能,让大家同步一下就行。

Q: 能只改名字不改邮箱吗?

可以:git commit --amend --author="新名字 <旧邮箱>" --no-edit

总结

改 Git 提交作者,记住几个场景:

  • 刚提交还没 push:git commit --amend,最简单
  • 之前某条提交要改:git rebase -i,精准定位
  • 批量改:git filter-branchgit filter-repo

核心原则:没 push 的随便改,push 过的要谨慎,改完记得通知团队成员同步。

以后再遇到用错账号的情况,照着上面的命令抄就行,不用慌。

在软件开发过程中,代码质量是一个永恒的话题。随着项目规模的扩大和团队成员的增加,如何保证代码质量成为一个挑战。SonarQube 作为一款开源的代码质量管理平台,能够帮助团队在开发过程中持续检测代码质量问题,是 DevOps 和 CI/CD 流程中不可或缺的工具。

SonarQube

什么是 SonarQube

SonarQube 是一个开源的代码质量管理平台,用于管理源代码的质量。它支持多种编程语言,包括 Java、C#、JavaScript、TypeScript、Python、PHP、Go 等 29+ 种语言。

SonarQube 通过静态代码分析,从以下七个维度检测代码质量:

  1. 可靠性 - 检测 Bug 和潜在的错误
  2. 安全性 - 发现安全漏洞和安全隐患
  3. 可维护性 - 检测代码异味(Code Smells)
  4. 覆盖率 - 单元测试覆盖率分析
  5. 重复度 - 检测重复代码块
  6. 复杂度 - 分析代码复杂度
  7. 文档 - 检查代码注释情况

SonarQube 架构

SonarQube 主要由以下几个组件组成:

1
2
3
4
┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│ Scanner │ ───► │ SonarQube │ ───► │ Database │
│ (代码扫描器) │ │ Server │ │ (数据库) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
  • Scanner:代码扫描器,负责分析源代码并将结果发送到 SonarQube Server
  • Server:SonarQube 服务器,负责处理分析结果、生成报告、提供 Web 界面
  • Database:存储配置信息、项目快照、分析结果等数据

安装部署

使用 Docker 快速部署

最简单的方式是使用 Docker Compose 部署 SonarQube:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
version: "3"

services:
sonarqube:
image: sonarqube:community
depends_on:
- db
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: sonar
volumes:
- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
- sonarqube_logs:/opt/sonarqube/logs
ports:
- "9000:9000"

db:
image: postgres:15-alpine
environment:
POSTGRES_USER: sonar
POSTGRES_PASSWORD: sonar
POSTGRES_DB: sonar
volumes:
- postgresql:/var/lib/postgresql
- postgresql_data:/var/lib/postgresql/data

volumes:
sonarqube_data:
sonarqube_extensions:
sonarqube_logs:
postgresql:
postgresql_data:

启动服务:

1
$ docker-compose up -d

访问 http://localhost:9000 即可打开 SonarQube Web 界面,默认账号密码为 admin/admin

系统要求

SonarQube 对系统有一定要求,特别是 Elasticsearch 组件:

1
2
3
4
5
# Linux 系统需要设置以下参数
$ sysctl -w vm.max_map_count=262144
$ sysctl -w fs.file-max=65536
$ ulimit -n 65536
$ ulimit -u 4096

可以将这些配置写入 /etc/sysctl.conf 文件使其永久生效。

代码扫描

安装 Scanner

SonarQube 提供了多种 Scanner 工具:

  • SonarScanner CLI - 通用命令行扫描器
  • SonarScanner for Maven - Maven 项目专用
  • SonarScanner for Gradle - Gradle 项目专用
  • SonarScanner for .NET - .NET 项目专用

安装 SonarScanner CLI

1
2
3
4
5
6
7
# 下载并解压
$ wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip
$ unzip sonar-scanner-cli-5.0.1.3006-linux.zip
$ mv sonar-scanner-5.0.1.3006-linux /opt/sonar-scanner

# 配置环境变量
$ export PATH=$PATH:/opt/sonar-scanner/bin

创建配置文件

在项目根目录创建 sonar-project.properties 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 项目基本配置
sonar.projectKey=my-project
sonar.projectName=My Project
sonar.projectVersion=1.0

# 源代码路径
sonar.sources=src
sonar.tests=tests

# 语言配置
sonar.language=php

# 排除不需要扫描的文件
sonar.exclusions=**/vendor/**,**/node_modules/**,**/tests/**

# 编码
sonar.sourceEncoding=UTF-8

执行扫描

1
2
3
4
5
# 登录 SonarQube 创建项目并获取 token
# 然后执行扫描
$ sonar-scanner \
-Dsonar.host.url=http://localhost:9000 \
-Dsonar.login=your_token_here

Maven 项目扫描

对于 Maven 项目,可以直接使用插件:

1
2
3
4
5
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.10.0.2594</version>
</plugin>

执行扫描:

1
2
3
$ mvn clean verify sonar:sonar \
-Dsonar.host.url=http://localhost:9000 \
-Dsonar.login=your_token_here

质量门禁

质量门禁(Quality Gate)是 SonarQube 的核心功能之一,用于定义代码质量的标准。只有通过质量门禁的代码才能被合并或部署。

默认质量门禁

SonarQube 提供了默认的质量门禁标准:

指标 条件
新代码覆盖率 >= 80%
新代码重复度 <= 3%
新代码中的 Bug = 0
新代码中的漏洞 = 0
新代码中的代码异味 = 0

自定义质量门禁

可以根据项目实际情况自定义质量门禁:

  1. 进入「Quality Gates」页面
  2. 点击「Create」创建新的质量门禁
  3. 添加条件,如:
    • Coverage < 50%
    • Duplicated Lines (%) > 5%
    • Maintainability Rating != A
  4. 将质量门禁设置为项目默认

代码规则与配置

SonarQube 内置了大量代码规则,涵盖多个方面:

规则类型

  • Bug - 可能导致程序错误的代码
  • Vulnerability - 安全漏洞
  • Code Smell - 代码异味,影响可维护性
  • Security Hotspot - 需要人工审查的安全敏感代码

质量配置

质量配置(Quality Profile)是规则的集合。可以:

  1. 继承内置配置并修改
  2. 激活或停用特定规则
  3. 调整规则严重级别(Blocker、Critical、Major、Minor、Info)
  4. 排除特定规则
1
2
3
4
# 示例:排除特定规则
sonar.issue.ignore.multicriteria=e1
sonar.issue.ignore.multicriteria.e1.ruleKey=php:S1234
sonar.issue.ignore.multicriteria.e1.resourceKey=**/*.php

与 CI/CD 集成

Jenkins 集成

安装 SonarQube Scanner for Jenkins 插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Jenkinsfile
pipeline {
agent any

stages {
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('My SonarQube Server') {
sh 'mvn clean verify sonar:sonar'
}
}
}

stage('Quality Gate') {
steps {
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
}
}

GitLab CI/CD 集成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# .gitlab-ci.yml
sonarqube-check:
image: maven:3.8.5-openjdk-17
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
GIT_DEPTH: "0"
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
script:
- mvn verify sonar:sonar -Dsonar.projectKey=${CI_PROJECT_NAME}
allow_failure: true
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_COMMIT_BRANCH == 'main'

GitHub Actions 集成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# .github/workflows/sonarqube.yml
name: SonarQube Scan
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened]

jobs:
sonarqube:
name: SonarQube
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

分支分析与 PR 装饰

分支分析

SonarQube Community 版本支持主分支分析,Developer 版本及以上支持多分支分析:

1
2
3
$ sonar-scanner \
-Dsonar.branch.name=feature-123 \
-Dsonar.branch.target=main

PR 装饰

Pull Request 装饰功能可以在 PR 中直接显示代码质量问题:

1
2
3
4
5
$ sonar-scanner \
-Dsonar.pullrequest.key=123 \
-Dsonar.pullrequest.branch=feature-123 \
-Dsonar.pullrequest.base=main \
-Dsonar.pullrequest.github.repository=myorg/myrepo

常用 API

SonarQube 提供了丰富的 REST API:

1
2
3
4
5
6
7
8
9
10
11
# 获取项目列表
$ curl -u token: http://localhost:9000/api/projects/search

# 获取项目质量门禁状态
$ curl -u token: http://localhost:9000/api/qualitygates/project_status?projectKey=my-project

# 获取问题列表
$ curl -u token: "http://localhost:9000/api/issues/search?componentKeys=my-project"

# 获取度量数据
$ curl -u token: "http://localhost:9000/api/measures/component?component=my-project&metricKeys=ncloc,coverage,bugs,vulnerabilities,code_smells"

最佳实践

1. 聚焦新代码

SonarQube 的「New Code」功能帮助你聚焦于新增和修改的代码,避免被历史债务淹没:

1
2
# 配置新代码周期
sonar.newCode.referenceBranch=main

2. 设置合理的质量门禁

不要过于激进,根据项目实际情况设置可达成的目标,逐步提升标准。

3. 定期清理技术债务

定期查看技术债务报告,安排时间修复高优先级问题。

4. 排除生成代码

自动生成的代码通常不需要扫描:

1
sonar.exclusions=**/generated/**,**/*_generated.php

5. 使用增量分析

对于大型项目,启用增量分析可以加快扫描速度:

1
sonar.analysis.cache.enabled=true

常见问题

1. 内存不足

如果扫描过程中出现内存不足错误,可以增加 Scanner 的内存:

1
$ export SONAR_SCANNER_OPTS="-Xmx2048m"

2. 编码问题

确保项目使用 UTF-8 编码:

1
sonar.sourceEncoding=UTF-8

3. 排除第三方代码

1
sonar.exclusions=**/vendor/**,**/node_modules/**,**/dist/**

版本对比

功能 Community Developer Enterprise Data Center
价格 免费 €150k/年 €250k/年 联系销售
语言支持 15+ 29+ 29+ 29+
分支分析 主分支 多分支 多分支 多分支
PR 装饰
安全报告 基础 完整 完整 完整
高可用

  1. 在地址栏输入 about:debugging
  2. 点击 This Firefox
  3. 找到目标扩展 → 点击 Inspect(调试)
  4. 在新打开的开发者工具中,切换到 Network 面板,即可看到该扩展发起的请求

upload successful

最近做项目要发邮件,什么注册确认、密码重置、订单通知,一堆功能都离不开邮件。PHP 自带的 mail() 函数?说实话,用过的都知道有多坑——配置麻烦、兼容性差、容易被当垃圾邮件。最后还是老老实实用 PHPMailer,踩了一些坑,今天把经验整理一下。

为什么是 PHPMailer

PHPMailer 是 PHP 里最老牌的邮件发送库,功能齐全:

  • 支持 SMTP 认证,TLS/SSL 加密
  • HTML 邮件、附件、嵌入式图片都能搞定
  • 抄送、密送、回复地址这些不在话下

环境要求:PHP 5.5 ~ 8.3,需要开启 mbstringopenssl 扩展。

安装

推荐用 Composer,省心:

1
composer require phpmailer/phpmailer

不想用 Composer 也行,去 GitHub 下载源码,手动引入文件。但都 2026 年了,还是 Composer 吧。

邮箱服务器配置

发邮件得有 SMTP 服务器,常用的 163 和 QQ 邮箱配置如下:

邮箱 SMTP 服务器 SSL 端口
163 smtp.163.com 465 或 994
QQ smtp.qq.com 465 或 587

重要提醒:163、QQ 这些邮箱默认关闭 SMTP 服务,得去邮箱设置里手动开启,然后生成一个「授权码」。后面代码里的密码填的是授权码,不是你的登录密码!

基础用法

直接上代码,能跑的才是好教程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'vendor/autoload.php';

$mail = new PHPMailer(true);

try {
// 服务器配置
$mail->CharSet = "UTF-8";
$mail->isSMTP();
$mail->Host = 'smtp.163.com';
$mail->SMTPAuth = true;
$mail->Username = 'your@163.com'; // 发件邮箱
$mail->Password = '授权码'; // 授权码,不是密码!
$mail->SMTPSecure = 'ssl';
$mail->Port = 465;

// 收发件人
$mail->setFrom('your@163.com', '发件人名字');
$mail->addAddress('receiver@example.com', '收件人名字');

// 邮件内容
$mail->isHTML(true);
$mail->Subject = '邮件标题';
$mail->Body = '<h1>这是 HTML 邮件内容</h1>';

$mail->send();
echo '发送成功';
} catch (Exception $e) {
echo "发送失败: {$mail->ErrorInfo}";
}

发送附件

加附件一行代码的事:

1
2
$mail->addAttachment('/path/to/file.zip');           // 普通附件
$mail->addAttachment('/path/to/image.jpg', '图片.jpg'); // 重命名附件

注意路径要写对,相对路径、绝对路径都行,但要确保文件存在。

嵌入图片到邮件正文

想在邮件正文里显示图片,有两种方式:一种是用 <img src="cid:图片id"> 配合 addEmbeddedImage,另一种是直接 base64 编码嵌入。推荐前者:

1
2
$mail->Body = '<h1>你好</h1><img src="cid:logo">';
$mail->addEmbeddedImage('images/logo.png', 'logo');

常见坑和解决方案

1. SMTP connect failed

最常见的错误。原因可能是:

  • SMTP 服务没开启(去邮箱设置里开)
  • 端口被防火墙拦截(换个端口试试:25、465、587)
  • 服务器地址写错了

2. 认证失败

大概率是密码填错了。163、QQ 邮箱要用授权码,不是登录密码。授权码在邮箱设置里生成。

3. 中文乱码

编码问题,加上这句:

1
$mail->CharSet = "UTF-8";

4. SSL 连接失败

检查 PHP 有没有开启 openssl 扩展,php.ini 里把 extension=openssl 前面的分号去掉,重启服务。

5. 邮件进了垃圾箱

原因很多:发件人和 SMTP 认证邮箱不一致、邮件内容太像广告、域名没有配置 SPF 记录。生产环境建议用专业邮件服务,比如 SendGrid、Mailgun,比自己搭 SMTP 靠谱。

调试技巧

开发阶段遇到问题,打开调试模式:

1
$mail->SMTPDebug = 2;  // 级别 0-4,数字越大越详细

调试完记得关掉,生产环境开调试会暴露敏感信息。

一个完整的例子

把上面的拼起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'vendor/autoload.php';

$mail = new PHPMailer(true);

try {
$mail->CharSet = "UTF-8";
$mail->SMTPDebug = 0; // 生产环境用 0
$mail->isSMTP();
$mail->Host = 'smtp.163.com';
$mail->SMTPAuth = true;
$mail->Username = 'your@163.com';
$mail->Password = 'your-authorization-code';
$mail->SMTPSecure = 'ssl';
$mail->Port = 465;

$mail->setFrom('your@163.com', 'l1n6yun');
$mail->addAddress('receiver@example.com');
$mail->addReplyTo('your@163.com', 'Reply');

// 附件
$mail->addAttachment('files/report.pdf');

$mail->isHTML(true);
$mail->Subject = '测试邮件';
$mail->Body = '<h2>邮件发送成功!</h2><p>这是一封测试邮件。</p>';
$mail->AltBody = '邮件发送成功!这是一封测试邮件。'; // 纯文本备用

$mail->send();
echo '邮件发送成功';
} catch (Exception $e) {
echo "邮件发送失败: {$mail->ErrorInfo}";
}

PHPMailer 用起来其实不难,主要是 SMTP 配置容易踩坑。记住几个要点:授权码、端口、编码、调试模式,基本就能搞定大部分场景了。

有问题欢迎评论区交流~

Image

插件简介:重新定义编码输入体验

1 开发者专属智能助手

身为开发者,日常在编码时,是不是常被输入法切换问题困扰?写代码时得用英文输入法,添加注释又得切换成中文输入法。反复按 Shift 键或使用组合快捷键,不仅麻烦,还容易打断思路。有时候,因为没注意输入法状态,输入一半才发现错了,只能删除重新输入 ,实在让人抓狂。

Smart Input Pro 就是一款专为解决这些痛点而生的插件,基于 IntelliJ 平台,在 IDEA、WebStorm、PyCharm 等这些大家日常开发常用的工具中,都可以安装使用。它就像一个贴心的智能助手,时刻监控你的输入场景,然后自动帮你在中英文输入法之间进行切换,从此你再也不用手动频繁切换输入法了。

2 核心设计理念

Smart Input Pro 之所以能实现如此智能的切换,得益于其 “场景感知 + 智能决策” 的先进架构。它就像一个聪明的观察者,会实时分析多个关键因素:

  • 光标位置:精确判断你当前输入的位置是在代码区、注释区,还是字符串内。

  • 代码上下文:理解代码的语法结构,知道哪些地方应该是英文代码,哪些地方是中文注释 。比如,当它检测到你在注释区域(单行注释//、多行注释/* */、文档注释/** */ )时,就会自动切换至中文输入法,方便你撰写说明;而在代码区域,则自动切换至英文输入法,确保代码语法正确。

  • 操作行为:留意你的操作动作,比如当你打开 Git 提交框准备填写提交信息时,它能识别提交框焦点,自动切换为中文输入法;当你使用 IdeaVim 模式时,在 NORMAL 模式下自动切换英文,确保命令正确执行。

通过综合分析这些因素,插件能够动态匹配最优输入法,整个过程自然流畅,让你在不知不觉中完成输入状态的切换,将全部的注意力都集中在代码逻辑本身,极大地提升了编码效率和专注度 。

核心功能:全场景覆盖的智能输入方案

1 场景化自动切换:精准捕捉输入需求

Smart Input Pro 的场景化自动切换功能十分强大,能精准识别各种输入场景,自动帮你切换到最合适的输入法 。

在代码编辑区,当你进入代码编写区域时,插件会迅速反应,自动切换为英文输入法,杜绝中文输入法下误输入全角符号(如 “,”“。”)导致的编译错误,为代码的准确性提供保障。它支持 JavaScript、Java、Vue 等主流语言,对字符串字面量还能进行智能识别。比如,当你输入nameEn="Tom" 时,它能判断这里应保持英文;而当输入nameCn="小明" ,则会自动唤醒中文 ,就像一个熟悉你代码习惯的伙伴,默默帮你处理好输入法的细节。

来到注释与文档区,当你输入单行注释(//)、多行注释(/**/)或 Markdown 文档时,它又会贴心地自动切换为中文输入法,而且完美兼容中英文混合输入场景,让注释撰写无比流畅。以编写 Javadoc 为例,中文描述与英文代码符号能在它的帮助下无缝衔接,你可以专注于内容表达,无需再为输入法切换分神 。

除了上述区域,在工具窗口与特殊场景中,它也能发挥作用。比如在 Git 提交框,当你输入 Commit Message 时,它自动切为中文,方便你规范地撰写中文提交说明;在终端(Terminal)/Project 窗口,它会强制英文输入,避免命令行中混入中文字符,保证命令执行顺畅;如果你使用 IdeaVim 模式,在 NORMAL 模式它自动切换为英文,INSERT 模式则按当前编辑场景智能切换,让 Vim 操作与输入法切换配合默契 。

2 可视化状态反馈:光标即输入状态指示器

为了让你随时了解当前的输入状态,Smart Input Pro 还提供了可视化状态反馈功能。

其中,三色光标提示十分直观,蓝色光标代表英文小写,紫色光标表示英文大写,红色光标则意味着中文输入 。在编码过程中,你无需将视线移至系统状态栏,只要看一眼光标颜色,就能快速确认输入状态,大大减少了误操作的概率。比如,当你看到红色光标时,就知道当前是中文输入法状态,可以放心输入中文内容;而看到蓝色光标,就明白现在适合输入英文代码 。

此外,还有轻量浮动标签,它会在光标附近显示 “EN” 或 “中文” 微型标签,这个标签支持自定义位置与透明度。你可以根据自己的习惯,将它调整到既不遮挡视线,又能轻松看到的位置,还能根据个人喜好设置透明度,兼顾提示性与无干扰性,让你在编码时随时掌握输入状态 。

3 高度可定制化:打造个人专属输入规则

每个人的编码习惯和项目需求都有所不同,Smart Input Pro 充分考虑到这一点,提供了高度可定制化的功能。

通过自定义正则匹配,你可以轻松定义特殊场景。例如,针对 i18n 相关文件(*.zh-CN.vue),你可以通过正则表达式让插件强制中文输入,确保国际化文件中的中文内容输入顺畅;或者在 SQL 脚本中,识别中文注释块并自动切为中文,满足特定的编程需求 。只需要简单编写正则表达式,就能让插件按照你的想法工作 。

它还有强大的输入法记忆机制。当你手动切换输入法后,插件会自动学习你的习惯。比如,在特定文件类型中,你偏好某种输入状态,它就会记住这个习惯,逐步优化切换策略,随着使用时间的增加,它会越来越 “懂你” ,让输入法的切换更加贴合你的使用习惯,为你打造个性化的编码输入环境 。

使用指南:三步开启智能输入之旅

1 快速安装与初始化

安装 Smart Input Pro 的过程非常简单,无论你是在线安装还是离线安装,都能轻松完成。

如果你选择在线安装,在 IDE 内打开插件市场,这就好比是一个插件的大超市,里面摆满了各种各样的插件 。在搜索框中输入 “Smart Input Pro”,就像在超市里寻找特定的商品一样,很快就能找到它。找到后,点击安装按钮,插件就会自动下载并安装到你的 IDE 中。安装完成后,按照提示重启 IDE,整个过程无需手动配置,就像拿到一个新的电子产品,打开就能用,真正做到了开箱即用 。

要是你处于网络受限的环境,也不用担心,还可以选择离线安装。你可以从 JetBrains 插件市场下载对应版本的 ZIP 文件,这个文件就像是一个装满插件的包裹 。下载好后,通过 “Install Plugin from Disk”(从磁盘安装插件)选项将下载的 ZIP 文件导入到 IDE 中,就像把包裹里的东西放进你的电脑里一样简单,轻松解决网络问题带来的困扰 。

2 基础配置优化

安装完成后,还需要进行一些基础配置,让插件更好地适应你的使用习惯 。

首先是选择默认中文输入法,在插件设置中,你可以指定自己常用的中文输入法,比如大家常用的搜狗输入法、百度输入法等 。这就像是给插件设定一个语言助手,让它知道你平时喜欢用哪种中文输入法,这样它就能在需要的时候精准地帮你切换,确保输入法的切换符合你的习惯 。

对于不同系统的用户,它还有一些专属的跨平台适配设置。Windows 用户可以启用 “离开 IDE 恢复系统输入法” 功能,当你离开 IDE 去做其他事情,再回到 IDE 时,输入法会自动恢复到你离开前在 IDE 中的设置,就像 IDE 记住了你离开时的输入法状态一样 。而 Mac 用户则更方便,插件支持全局输入法状态记忆,当你在不同应用之间切换时,它会自动还原你的输入环境,比如你从 IDE 切换到浏览器,再切回 IDE,输入法还是你在 IDE 中使用时的状态,让你的输入体验更加流畅 。

3 进阶设置:释放插件潜力

如果你想要进一步发挥插件的强大功能,还可以进行进阶设置 。

通过自定义场景规则,你可以打造适合自己的输入逻辑。进入 “Settings> Smart Input Pro > Custom Rules”(设置 > Smart Input Pro > 自定义规则),在这里,你可以针对特定的文件路径、代码块结构添加专属的切换逻辑 。比如,在一个 Vue 项目中,你希望 Vue 模板中的中文文案区域始终保持中文输入,就可以在这里进行设置。通过编写规则,让插件识别 Vue 模板文件,当光标进入中文文案区域时,自动切换并保持中文输入法状态,让你的代码编写更加高效 。

对于使用低配设备的开发者,为了平衡智能度与流畅度,还可以开启 “轻量模式” 。开启后,插件会降低资源占用,就像给插件 “瘦身” 一样,让它在低配设备上也能轻松运行,不会因为占用过多资源而导致设备卡顿,让你在享受智能输入的同时,也能保证设备的流畅运行 。

实战案例:从低效切换到丝滑编码

1 典型开发场景对比

为了让大家更直观地感受到 Smart Input Pro 带来的效率提升,我们来看一下实际开发场景中使用插件前后的对比 。

在未使用插件之前,开发过程中充满了各种因输入法切换带来的困扰。就拿编写代码来说,平均每 5 分钟,我就会因为输入法的问题而出现 1 次输入状态错误。比如在定义变量名时,本应使用英文输入法输入字母,却因为疏忽还停留在中文输入法状态,结果输入了全角字符,导致代码出现语法错误 。在添加注释时,也经常会因为没有及时切换输入法,使得注释中混入英文符号,或者在代码中出现中文标点,这不仅影响了代码的可读性,还需要花费额外的时间去反复检查修正 。

而使用 Smart Input Pro 插件后,情况就大不一样了 。在代码区,它会自动切换为英文输入法,确保我输入的代码准确无误;在注释区,又会自动切换为中文输入法,让我可以流畅地撰写注释 。就连在 Git 提交时,也无需手动切换输入法,直接就能用中文输入提交信息 。根据我的统计,使用插件后,日均减少了 200 + 次无效切换操作,编码时的专注度也提升了 30% ,真正实现了从低效到高效的转变 。

2 具体操作演示(以 Vue 开发为例)

接下来,以 Vue 开发为例,为大家详细演示一下 Smart Input Pro 插件的具体使用过程 。

<template>标签内编写代码时,当我输入v-model,准备补全变量名,此时插件会保持英文输入法状态,让我可以毫无干扰地输入英文变量名 。比如输入v-model="userName" ,整个输入过程非常流畅,不用担心输入法的问题 。

当切换到<script>的注释区域,我输入// 按钮点击事件 ,插件会自动切换为中文输入法,我可以直接输入中文描述,快速完成注释内容的编写 。像// 点击按钮后,调用接口获取数据 ,轻松就能完成输入 。

当打开 Git 提交窗口,准备输入提交信息时,比如输入 “修复表单验证逻辑” ,此时无需手动切换输入法,因为插件已经自动将输入法切换为中文,直接输入即可,大大提高了提交效率 。

进入终端输入npm run dev时,插件会强制将输入法切换为英文,避免因为误输入中文而导致命令错误 。即使我不小心按下了中文输入法快捷键,插件也能迅速调整回来,确保命令的正确执行 。

优缺点分析:客观评估插件价值

1 核心优势

  • 效率提升显著:在日常开发中,我们常常会因为频繁切换输入法而打断思路,降低编码效率 。而 Smart Input Pro 的自动切换功能十分强大,它能够覆盖 90% 以上的常规场景,让我们无需手动切换输入法,从而将更多的时间和精力投入到代码的编写中。以我个人的使用体验为例,在使用该插件之前,我每天需要花费大量的时间在输入法切换上,而使用之后,这些时间被节省了下来,我可以更加专注地思考代码逻辑,编码效率得到了大幅提升 。

  • 错误预防能力:在代码编写过程中,因符号错误导致的编译问题是我们经常会遇到的困扰 。而 Smart Input Pro 通过场景化输入法控制,能够有效地避免这类问题的发生。它会在我们输入代码时,自动切换为英文输入法,确保我们输入的符号都是正确的;而在输入注释时,又会自动切换为中文输入法,方便我们撰写注释 。根据实际使用情况统计,使用该插件后,因符号错误导致的编译问题降低了 80%+,大大提高了代码的质量和开发效率 。

  • 学习成本极低:对于开发者来说,学习新工具的成本是一个重要的考虑因素 。而 Smart Input Pro 的默认配置即满足多数需求,即使是初次使用的用户,也能快速上手。对于一些进阶功能,它还提供了图形化界面操作,我们只需要通过简单的设置,就能轻松实现个性化的需求,无需编写复杂的规则 。这使得我们能够在短时间内熟练掌握插件的使用方法,快速提升编码效率 。

2 改进空间

  • 硬件兼容性:在配置较低的电脑上,当我们处理复杂项目时,Smart Input Pro 可能会出现轻微光标延迟的情况 。这是因为插件在运行过程中需要占用一定的系统资源,而配置较低的电脑可能无法满足其需求 。不过,我们可以通过开启轻量模式来缓解这一问题。轻量模式下,插件会降低对系统资源的占用,从而提高运行的流畅度 。虽然开启轻量模式后,插件的一些智能功能可能会受到一定影响,但对于配置较低的电脑用户来说,这仍然是一个不错的解决方案 。

  • 高级功能付费:Smart Input Pro 的高级功能,如自定义正则匹配、多设备同步等,需要订阅专业版才能使用 。对于一些对功能要求较高的用户来说,这可能会增加一定的使用成本 。专业版的月费约 10 元,虽然价格不算高,但对于一些个人开发者或小型团队来说,可能还是会有些犹豫 。不过,免费版已经包含了核心切换功能,能够满足大多数用户的日常需求 。如果用户对高级功能的需求不是很迫切,那么使用免费版也完全可以 。

总结与推荐:谁该拥有这款神器?

1 适合人群

  • 中文开发者:如果你是一位中文开发者,日常开发中需要频繁在代码与中文注释、文档间切换,那么 Smart Input Pro 绝对是你的得力助手。它能自动识别输入场景,在代码区自动切换为英文输入法,在注释和文档区自动切换为中文输入法,让你无需手动切换,专注于代码的编写和逻辑的实现 。尤其是对于 Java、前端、全栈等领域的开发者,这款插件的实用性更强,能够有效提高你的开发效率 。

  • 效率敏感型开发者:对于那些追求高效开发,希望减少重复性操作,将更多精力聚焦于逻辑实现而非工具切换的人群来说,Smart Input Pro 无疑是一个绝佳的选择 。它的自动切换功能能够极大地减少无效操作,让你在编码过程中保持流畅的思路,将更多的时间和精力投入到真正有价值的工作中 。

  • Vim/Emacs 用户:如果你是 Vim/Emacs 用户,在使用 IDEA 等开发工具时,常常被 IDE 快捷键与输入法切换间的频繁冲突所困扰,那么 Smart Input Pro 可以完美解决你的问题 。它能够与 IdeaVim 等模式完美适配,在 NORMAL 模式下自动切换英文,确保命令正确执行;在 INSERT 模式下则按当前编辑场景智能切换,让你的 Vim 操作与输入法切换配合得更加默契 。

在 Windows 11 下使用 WSL2 开发 PHP 项目时,断点调试是提升效率的关键。本文将详细讲解如何基于 Alpine Linux v3.18 配置 PhpStorm + XDebug 环境,解决版本兼容、路径映射、调试连接等核心问题,适用于 Hyperf、Laravel 等主流 PHP 框架。

环境说明

先明确本地开发环境的核心信息,避免后续配置因版本不匹配导致失败:

组件 版本/信息 说明
宿主机系统 Windows 11 需已启用 WSL2(需先开启虚拟机平台功能)
WSL2 发行版 Alpine Linux v3.18 已更换阿里云源(安装速度更快)
PHP 版本 8.1.2 需与 XDebug 版本兼容
XDebug 版本 3.2.2 对应 PHP 8.1 的 PECL 包
调试框架示例 Hyperf 3.x 也适用于 Laravel、ThinkPHP 等
PhpStorm 版本 2023.x 及以上 确保支持 XDebug 3.x

前置准备

在开始配置前,需完成以下基础操作:

  1. 启用 WSL2 并安装 Alpine:参考 微软官方文档,确保 Alpine 能正常通过 wsl 命令启动。
  2. 更换 Alpine 国内源:默认源速度较慢,需先替换为阿里云源(否则后续安装 XDebug 可能失败):
    1
    2
    3
    4
    5
    6
    7
    # 编辑源配置文件
    vi /etc/apk/repositories
    # 替换为阿里云源(Alpine 3.18)
    https://mirrors.aliyun.com/alpine/v3.18/main
    https://mirrors.aliyun.com/alpine/v3.18/community
    # 更新源缓存
    apk update
  3. 确认 PHP 已安装:在 WSL 中执行 php -v,确保输出 PHP 8.1.2 信息(若未安装,需先通过 apk add php81 php81-cli php81-common 安装)。

步骤 1:安装 XDebug(WSL 内操作)

XDebug 需通过 Alpine 的 PECL 仓库安装,且必须选择与 PHP 版本匹配的包(PHP 8.1 对应 php81-pecl-xdebug)。

1 搜索匹配的 XDebug 包

先确认仓库中是否有对应 PHP 版本的 XDebug:

1
apk search xdebug

输出结果中需包含 php81-pecl-xdebug-3.2.2-r0(若显示 php82-* 则为 PHP 8.2 版本,请勿安装,避免版本不兼容)。

2 安装 XDebug

执行安装命令,Alpine 会自动处理依赖:

1
apk add php81-pecl-xdebug

安装成功后,执行以下命令验证是否加载 XDebug 扩展:

1
php -v

若输出中包含 with Xdebug v3.2.2,说明安装成功:

1
2
3
4
PHP 8.1.2 (cli) (built: Feb  1 2023 12:05:42) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Xdebug v3.2.2, Copyright (c) 2002-2023, by Derick Rethans

步骤 2:配置 XDebug(关键!避免调试失败)

XDebug 3.x 与 2.x 配置差异较大,需编辑专属配置文件,核心是指定「调试模式」「宿主机地址」「端口」。

1 找到 XDebug 配置文件

Alpine 中 PHP 8.1 的 XDebug 配置文件路径固定为:

1
vi /etc/php81/conf.d/50_xdebug.ini

2 写入配置内容

将以下内容复制到文件中,每个配置项都有详细注释,无需额外修改(host.docker.internal 是 WSL2 内置的「宿主机 IP 别名」,无需手动查宿主机 IP):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
; 启用 XDebug 扩展(必须放在最前面)
zend_extension=xdebug.so

; 调试模式:debug(断点调试)+ develop(开发辅助,如错误提示)
xdebug.mode=debug,develop

; 自动发现客户端主机(WSL 环境下建议开启,避免手动改 IP)
xdebug.discover_client_host=true

; 强制指定宿主机地址(WSL2 专用,指向 Windows 宿主机)
xdebug.client_host=host.docker.internal

; 调试端口(默认 9003,需与 PhpStorm 保持一致,避免冲突)
xdebug.client_port=9003

; IDE 标识(必须与 PhpStorm 配置的 IDE Key 一致,默认 PHPSTORM)
xdebug.idekey=PHPSTORM

; 请求启动时自动触发调试(无需手动触发,开发更便捷)
xdebug.start_with_request=yes

; 显示详细调试日志(调试失败时可开启,日志路径自行指定)
; xdebug.log=/var/log/xdebug.log

3 验证配置生效

配置后需重启 PHP 服务(若用 Hyperf 等框架,重启服务即可),并执行以下命令确认配置:

1
php -i | grep XDebug

输出中需包含 xdebug.mode => debug,develop xdebug.client_port => 9003 等信息,说明配置正确。

步骤 3:添加环境变量(关联 PhpStorm 服务器)

需在 WSL 中设置 PHP_IDE_CONFIG 环境变量,指定 PhpStorm 中配置的「服务器名称」,确保路径映射生效。

1 写入环境变量

执行以下命令,将环境变量添加到 ~/.bashrc(若用 Zsh 则改为 ~/.zshrc):

1
2
3
4
5
# 写入环境变量(SomeName 可自定义,后续 PhpStorm 需用相同名称)
echo 'export PHP_IDE_CONFIG="serverName=SomeName"' >> ~/.bashrc

# 立即生效环境变量(无需重启 WSL)
source ~/.bashrc

2 验证环境变量

执行 echo $PHP_IDE_CONFIG,输出 serverName=SomeName 即成功。

步骤 4:配置 PhpStorm(宿主机操作)

PhpStorm 需配置「PHP 解释器」「服务器」「XDebug 端口」,核心是解决「WSL 路径与 Windows 路径映射」问题(断点不命中的常见原因)。

1 配置 PHP 解释器(关联 WSL 中的 PHP)

  1. 打开 PhpStorm → 进入 File > Settings > PHP(Windows/Linux)或 PhpStorm > Settings > PHP(Mac)。
  2. 点击「CLI Interpreter」右侧的 ... → 点击左上角 + → 选择「From Docker, Vagrant, WSL, Remote…」。
  3. 在弹出的窗口中选择「WSL」→ 选择已安装的「Alpine Linux」→ 自动识别 PHP 路径(通常为 /usr/bin/php81)→ 点击「OK」。
  4. 回到 PHP 配置页,确保「CLI Interpreter」已选中 WSL 中的 PHP 8.1。

2 配置服务器(路径映射关键)

  1. 进入 File > Settings > PHP > Servers → 点击左上角 +,配置以下信息:
    • Name:输入 SomeName(必须与 WSL 中 serverName 一致!)。
    • Host:输入项目的访问地址(如 Hyperf 项目默认 127.0.0.1,Laravel 项目可能为 localhost)。
    • Port:输入项目端口(如 Hyperf 默认 9501,Laravel 默认 8000)。
    • Debugger:选择 XDebug
    • Use path mappings:必须勾选!然后配置「本地路径 ↔ WSL 路径」:
      • 左侧「Local Path」:选择 Windows 中项目的本地路径(如 D:\projects\hyperf-demo)。
      • 右侧「Remote Path」:选择 WSL 中项目的路径(如 /home/user/hyperf-demo)。
  2. 点击「OK」保存。

3 配置 XDebug 端口

  1. 进入 File > Settings > PHP > Debug > XDebug
  2. 确认「Debug port」为 9003(与 WSL 中 xdebug.client_port 一致)。
  3. 勾选「Allow connection to unprofiled scripts」→ 点击「OK」。

步骤 5:启动调试侦听(PhpStorm 操作)

PhpStorm 需要主动「侦听」WSL 发送的调试请求,步骤如下:

  1. 点击 PhpStorm 右上角的「电话」图标(Hover 显示「Start Listening for PHP Debug Connections」),图标变亮表示已启动侦听。
  2. (可选)开启「断点自动触发」:点击「小虫子」图标(Hover 显示「Debug ‘当前项目名’」),或按快捷键 Shift + F9

验证侦听是否成功

在 Windows 中打开「命令提示符(CMD)」,执行以下命令查看 9003 端口是否被 PhpStorm 占用:

1
netstat -ano | findstr 9003

若输出以下内容(LISTENING 状态),说明侦听正常:

1
2
TCP    0.0.0.0:9003           0.0.0.0:0              LISTENING       31268  # 31268 是 PhpStorm 进程 ID
TCP [::]:9003 [::]:0 LISTENING 31268

步骤 6:启动项目并验证调试连接

以 Hyperf 项目为例,在 WSL 中启动项目,然后验证 PhpStorm 与 WSL 的连接。

1 启动 PHP 项目(WSL 内)

进入项目根目录,执行启动命令(不同框架命令不同):

1
2
# Hyperf 项目启动命令
php bin/hyperf.php start

启动成功后输出:

1
2
[INFO] Worker#0 started.
[INFO] HTTP Server listening at 0.0.0.0:9501

2 验证调试连接(Windows CMD)

再次执行端口监听命令,查看是否出现「ESTABLISHED」状态(表示 WSL 与 PhpStorm 已建立连接):

1
netstat -ano | findstr 9003

成功连接的输出:

1
2
3
TCP    0.0.0.0:9003           0.0.0.0:0              LISTENING       31268
TCP 172.23.240.1:9003 172.23.252.48:43416 ESTABLISHED 31268 # 新增的连接
TCP [::]:9003 [::]:0 LISTENING 31268

步骤 7:断点调试(核心操作)

连接成功后,即可通过断点调试查看变量、调用栈等信息,以 Hyperf 控制器为例:

  1. 打断点:在 PhpStorm 中打开 app/Controller/IndexController.php,在 index 方法的第一行代码左侧点击,出现红色圆点(断点)。
  2. 触发请求:在 Windows 浏览器中访问 http://127.0.0.1:9501(Hyperf 默认接口),或用 Postman 发送请求。
  3. 查看调试面板:请求触发后,PhpStorm 会自动弹出调试面板,包含以下核心信息:
    • Frames:查看函数调用栈。
    • Variables:查看当前作用域的变量值(如请求参数、数据库查询结果)。
    • Watches:手动添加需要监控的变量。
  4. 调试控制:使用 PhpStorm 底部的调试工具栏控制流程:
    • F8:单步执行(跳过函数内部)。
    • F7:单步进入(进入函数内部)。
    • Shift + F8:单步跳出(从函数内部跳出)。
    • F9:继续执行(直到下一个断点)。

常见问题排查(避坑指南)

断点不命中?

  • 原因 1:路径映射错误 → 检查 PhpStorm 服务器配置中的「Local Path」与「Remote Path」是否完全对应(如 Windows 路径带 \,WSL 路径带 /)。
  • 原因 2:XDebug 配置错误 → 执行 php -i | grep XDebug,确认 xdebug.mode 包含 debugxdebug.client_hosthost.docker.internal
  • 原因 3:端口被占用 → 用 netstat -ano | findstr 9003 查看是否有其他进程占用 9003 端口,若有则修改 xdebug.client_port 为其他端口(如 9004),并同步更新 PhpStorm 配置。

无法连接到 XDebug?

  • 原因 1:PhpStorm 未启动侦听 → 确认右上角「电话」图标已亮。
  • 原因 2:WSL 网络问题 → 尝试手动指定宿主机 IP(替换 xdebug.client_host 为 Windows 的局域网 IP,如 192.168.1.100)。
  • 原因 3:XDebug 日志未开启 → 开启 xdebug.log=/var/log/xdebug.log,查看日志中的错误信息(如 Could not connect to client host)。

PHP 版本与 XDebug 不兼容?

  • 症状:执行 php -v 不显示 XDebug 信息 → 确保安装的 XDebug 包与 PHP 版本匹配(PHP 8.1 对应 php81-pecl-xdebug,PHP 8.2 对应 php82-pecl-xdebug)。

总结

通过以上步骤,即可在 Windows 11 + WSL2(Alpine)环境下实现 PhpStorm 与 XDebug 的无缝调试。核心是「版本匹配」「路径映射」「端口一致」三个关键点,遇到问题时优先查看 XDebug 日志和端口监听状态,大部分问题可快速定位解决。

0%