1. 从跑通到稳定:一个老PHPer的成长历程
2005年,当我第一次在本地环境成功运行PHP脚本时,那种兴奋感至今难忘。屏幕上简单的一行"Hello World",背后却是无数次配置失败的尝试。那时的PHP开发环境搭建就像在玩扫雷——Apache配置、PHP模块加载、MySQL连接,每一步都可能踩到"雷区"。
早期的PHP开发充满了这种"跑通就开心"的单纯快乐。我们使用Dreamweaver这类可视化工具拖拽页面,在PHP代码中直接混写HTML和SQL,甚至会把数据库连接字符串硬编码在页面顶部。记得有一次,我为了在页面上显示一个简单的用户列表,写了将近200行的代码,其中大部分是重复的表格标签和字符串拼接。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从野蛮生长到规范开发
随着项目规模扩大,这种开发方式的弊端逐渐显现。最痛苦的经历是维护一个包含300多个混编文件的电商系统——修改一个页面布局需要同时改动十几个文件,添加新功能时根本记不清哪些变量已经在全局范围内被使用。
PSR标准的出现改变了这一切。当我第一次尝试按照PSR-1和PSR-2规范重构代码时,才意识到之前的代码有多么难以维护。以下是一个典型的前后对比:
php复制// 重构前
function getUsers(){global $db;
$q="SELECT * FROM users";$r=mysqli_query($db,$q);
while($row=mysqli_fetch_array($r)){echo '<tr><td>'.$row['name'].'</td></tr>';}}
// 重构后
class UserRepository {
private $connection;
public function __construct(PDO $connection) {
$this->connection = $connection;
}
public function findAll(): array {
$stmt = $this->connection->query('SELECT * FROM users');
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
这种转变不仅仅是代码风格的变化,更是开发思维的升级。我开始理解到:
- 单一职责原则让每个类只做一件事
- 依赖注入使代码更易于测试
- 类型声明减少了运行时错误
- 分离业务逻辑和展示层提高了可维护性
3. 现代PHP开发的核心要素
3.1 框架的选择与使用
Laravel的出现彻底改变了PHP开发的体验。它提供的Eloquent ORM让我从繁琐的SQL字符串拼接中解放出来。以下是一个典型的数据操作对比:
php复制// 传统方式
$sql = "INSERT INTO posts (title, content) VALUES ('".mysqli_real_escape_string($title)."', '".mysqli_real_escape_string($content)."')";
mysqli_query($db, $sql);
$newId = mysqli_insert_id($db);
// Eloquent方式
$post = Post::create([
'title' => $title,
'content' => $content
]);
但框架不是银弹。我曾在项目中遇到过过度依赖框架特性导致的问题:
- 盲目使用魔术方法导致代码难以追踪
- 过度抽象造成的性能瓶颈
- 框架版本升级带来的兼容性问题
3.2 数据库交互的进化
从最初的mysql_函数到PDO,再到现在的ORM,PHP的数据库交互方式发生了巨大变化。以下是我总结的几个关键经验:
- 永远使用预处理语句防止SQL注入
- 在事务中处理关联操作
- 合理使用索引提高查询性能
- 避免N+1查询问题
php复制// 典型的N+1问题
$users = User::all();
foreach ($users as $user) {
echo $user->profile->name; // 每次循环都执行一次查询
}
// 优化后的写法
$users = User::with('profile')->get();
3.3 测试驱动开发
从"写完就扔"到测试驱动开发,这个转变花了最长时间。但当我第一次因为单元测试发现了一个潜在的生产环境bug时,就彻底成为了TDD的信徒。PHPUnit现在是我每个项目的标配:
php复制class OrderTest extends TestCase {
public function test_order_total_calculation() {
$order = new Order();
$order->addItem(new Item(['price' => 100]));
$order->addItem(new Item(['price' => 200]));
$this->assertEquals(300, $order->calculateTotal());
}
}
4. 生产环境稳定性的保障
4.1 性能优化实践
让代码跑通只是开始,让它稳定高效运行才是真正的挑战。以下是我积累的一些性能优化经验:
- OPcache配置:确保opcache.enable=1,并合理设置内存大小
- 避免在循环中执行查询或创建对象
- 使用缓存减轻数据库压力
- 合理处理日志级别,避免过度IO
php复制// 糟糕的性能写法
foreach ($ids as $id) {
$result[] = DB::table('large_table')->where('id', $id)->first();
}
// 优化写法
$results = DB::table('large_table')->whereIn('id', $ids)->get();
$result = collect($results)->keyBy('id');
4.2 错误处理与日志
从最初的error_reporting(E_ALL)到现在的Monolog集成,错误处理方式也经历了巨大变化。我的经验法则是:
- 在生产环境关闭display_errors
- 使用try-catch处理预期内的异常
- 记录有意义的错误上下文
- 实现监控告警机制
php复制try {
$payment = processPayment($order);
} catch (PaymentException $e) {
Log::error('支付处理失败', [
'order_id' => $order->id,
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
notifyAdmin($e);
throw new OrderException('支付处理失败,请稍后重试');
}
4.3 持续集成与部署
从FTP上传文件到现在的GitOps工作流,部署方式的变化大大提高了稳定性。我现在的基本流程:
- 代码提交触发CI流水线
- 运行单元测试和静态分析
- 构建Docker镜像
- 部署到测试环境进行验收
- 蓝绿部署到生产环境
yaml复制# 简单的GitLab CI配置示例
stages:
- test
- build
- deploy
phpunit:
stage: test
script:
- composer install
- vendor/bin/phpunit
build_image:
stage: build
script:
- docker build -t myapp:$CI_COMMIT_SHA .
deploy_staging:
stage: deploy
script:
- kubectl set image deployment/myapp myapp=myapp:$CI_COMMIT_SHA
5. 老PHPer的现代工具箱
经过这些年的积累,我的开发工具箱已经完全不同了:
- 本地开发:Docker + Laravel Sail
- 调试工具:Xdebug + PHPStorm
- 静态分析:PHPStan + Psalm
- 性能分析:Blackfire
- 文档工具:Swagger + Markdown
特别是Docker,它彻底解决了"在我机器上能跑"的问题。一个简单的docker-compose.yml就能定义完整的开发环境:
yaml复制version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
volumes:
- .:/var/www/html
depends_on:
- mysql
- redis
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: myapp
redis:
image: redis:alpine
回头看这十多年的PHP开发生涯,最大的感悟是:写出能运行的代码很容易,写出稳定、可维护的代码才是真正的挑战。从"跑通就开心"到"稳定才是王道"的转变,不仅是技术的进步,更是职业态度的成熟。
现在的PHP生态已经完全不同往日——Composer管理依赖、PSR规范代码、框架提供架构、Docker封装环境。作为老PHPer,我们需要不断学习新工具新思想,但同时也要记住:工具再变,对代码质量的追求永远不变。
