找回密码
 立即注册
首页 业界区 业界 2025 PHP 开发者必看得 25 个容易犯的常见错误 90% 的开 ...

2025 PHP 开发者必看得 25 个容易犯的常见错误 90% 的开发者都踩过

祉遛吾 2025-10-1 17:26:05
2025 PHP 开发者必看得 25 个容易犯的常见错误 90% 的开发者都踩过

前言

PHP 发展到今天,新特性层出不穷,最佳实践也在不断更新。写出干净、高效、好维护的代码,对每个 PHP 开发者来说都很重要。
这篇文章总结了 PHP 开发中最容易踩的坑,以及对应的解决方案。
不管你是刚入门还是已经写了很多年 PHP,相信都能从中找到有用的东西。
原文链接-2025 PHP 开发者必看得 25 个容易犯的常见错误 90% 的开发者都踩过
常见错误和解决方案

用 == 比较,结果不符合预期
  1. // 错误做法
  2. function isUserActive($status) {
  3.     if ($status == true) {  // '1', 1, true, 'true' 都会被判断为 true
  4.         return true;
  5.     }
  6.     return false;
  7. }
  8. // 正确做法
  9. function isUserActive(bool $status): bool {
  10.     return $status === true;
  11. }
复制代码
直接访问数组元素,没检查是否存在
  1. // 错误做法
  2. function getUserName($user) {
  3.     return $user['name'];  // name 不存在就报错了
  4. }
  5. // 正确做法
  6. function getUserName(array $user): string {
  7.     return $user['name'] ?? 'Unknown';  // 用 ?? 操作符兜底
  8. }
复制代码
在循环里拼接字符串,性能很差
  1. // 错误做法
  2. function buildReport(array $items): string {
  3.     $report = '';
  4.     foreach ($items as $item) {
  5.         $report = $report . $item->description;  // 每次都创建新字符串
  6.     }
  7.     return $report;
  8. }
  9. // 正确做法
  10. function buildReport(array $items): string {
  11.     $reports = [];
  12.     foreach ($items as $item) {
  13.         $reports[] = $item->description;
  14.     }
  15.     return implode('', $reports);
  16. }
复制代码
SQL 语句直接拼接参数,有注入风险
  1. // 错误做法
  2. function findUser($db, $userId) {
  3.     return $db->query("SELECT * FROM users WHERE id = " . $userId);  // 这样写有 SQL 注入风险
  4. }
  5. // 正确做法
  6. function findUser(PDO $db, int $userId): ?array {
  7.     $stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
  8.     $stmt->execute([$userId]);
  9.     return $stmt->fetch(PDO::FETCH_ASSOC);
  10. }
复制代码
读取文件时不做错误处理
  1. // 错误做法
  2. function readConfig($filename) {
  3.     $content = file_get_contents($filename);  // 文件不存在或读取失败怎么办?
  4.     return json_decode($content);
  5. }
  6. // 正确做法
  7. function readConfig(string $filename): array {
  8.     if (!file_exists($filename)) {
  9.         throw new RuntimeException("文件不存在: $filename");
  10.     }
  11.     $content = file_get_contents($filename);
  12.     if ($content === false) {
  13.         throw new RuntimeException("读取文件失败: $filename");
  14.     }
  15.     $data = json_decode($content, true);
  16.     if (json_last_error() !== JSON_ERROR_NONE) {
  17.         throw new RuntimeException("JSON 格式有问题: " . json_last_error_msg());
  18.     }
  19.     return $data;
  20. }
复制代码
函数参数和返回值不声明类型
  1. // 错误做法
  2. function calculateTotal($price, $quantity) {
  3.     return $price * $quantity;
  4. }
  5. // 正确做法
  6. function calculateTotal(float $price, int $quantity): float {
  7.     return $price * $quantity;
  8. }
复制代码
用 @ 符号屏蔽错误,问题难排查
  1. // 错误做法
  2. function getImageSize($filename) {
  3.     return @getimagesize($filename);  // 静默抑制错误
  4. }
  5. // 正确做法
  6. function getImageSize(string $filename): ?array {
  7.     if (!file_exists($filename)) {
  8.         return null;
  9.     }
  10.     $size = getimagesize($filename);
  11.     return $size !== false ? $size : null;
  12. }
复制代码
不用命名空间,污染全局环境
  1. // 错误做法 - 污染全局命名空间
  2. class User {}
  3. class Order {}
  4. // 正确做法
  5. namespace App\Models;
  6. class User {}
  7. namespace App\Orders;
  8. class Order {}
复制代码
捕获异常时太筼统,不区分类型
  1. // 错误做法
  2. function processOrder($order) {
  3.     try {
  4.         // 处理订单
  5.     } catch (Exception $e) {
  6.         error_log($e->getMessage());  // 通用的异常捕获
  7.     }
  8. }
  9. // 正确做法
  10. function processOrder(Order $order): void {
  11.     try {
  12.         // 处理订单
  13.     } catch (DatabaseException $e) {
  14.         // 处理数据库相关错误
  15.         throw new OrderProcessingException("处理订单时数据库错误", 0, $e);
  16.     } catch (ValidationException $e) {
  17.         // 处理验证相关错误
  18.         throw new OrderProcessingException("订单验证失败", 0, $e);
  19.     }
  20. }
复制代码
没用 PHP 8 的构造器属性提升
  1. // 错误做法
  2. class Customer {
  3.     private string $name;
  4.     private string $email;
  5.     public function __construct(string $name, string $email) {
  6.         $this->name = $name;
  7.         $this->email = $email;
  8.     }
  9. }
  10. // 正确做法
  11. class Customer {
  12.     public function __construct(
  13.         private string $name,
  14.         private string $email,
  15.     ) {}
  16. }
复制代码
不用 PHP 8 的空安全操作符 ?->
  1. // 错误做法
  2. function getCountryName($user) {
  3.     if ($user !== null &&
  4.         $user->getAddress() !== null &&
  5.         $user->getAddress()->getCountry() !== null) {
  6.         return $user->getAddress()->getCountry()->getName();
  7.     }
  8.     return null;
  9. }
  10. // 正确做法
  11. function getCountryName(?User $user): ?string {
  12.     return $user?->getAddress()?->getCountry()?->getName();
  13. }
复制代码
数组操作不够高效
  1. // 错误做法
  2. function findUser(array $users, string $email): ?array {
  3.     foreach ($users as $user) {
  4.         if ($user['email'] === $email) {
  5.             return $user;
  6.         }
  7.     }
  8.     return null;
  9. }
  10. // 正确做法
  11. function findUser(array $users, string $email): ?array {
  12.     return array_filter(
  13.         $users,
  14.         fn($user) => $user['email'] === $email
  15.     )[0] ?? null;
  16. }
复制代码
不用数组解构,代码冗余
  1. // 错误做法
  2. function processCoordinates($point) {
  3.     $x = $point[0];
  4.     $y = $point[1];
  5.     return sqrt($x * $x + $y * $y);
  6. }
  7. // 正确做法
  8. function processCoordinates(array $point): float {
  9.     [$x, $y] = $point;
  10.     return sqrt($x * $x + $y * $y);
  11. }
复制代码
日期处理用时间戳,不用 DateTime
  1. // 错误做法
  2. function isUserActive($lastLoginTimestamp) {
  3.     return (time() - $lastLoginTimestamp) < (30 * 24 * 60 * 60);
  4. }
  5. // 正确做法
  6. function isUserActive(DateTime $lastLogin): bool {
  7.     $thirtyDaysAgo = new DateTime('-30 days');
  8.     return $lastLogin > $thirtyDaysAgo;
  9. }
复制代码
还在用 switch,不用 PHP 8 的 match
  1. // 错误做法
  2. function getStatusMessage($status) {
  3.     switch ($status) {
  4.         case 'pending':
  5.             return '订单待处理';
  6.         case 'processing':
  7.             return '订单处理中';
  8.         case 'completed':
  9.             return '订单已完成';
  10.         default:
  11.             return '未知状态';
  12.     }
  13. }
  14. // 正确做法
  15. function getStatusMessage(string $status): string {
  16.     return match($status) {
  17.         'pending' => '订单待处理',
  18.         'processing' => '订单处理中',
  19.         'completed' => '订单已完成',
  20.         default => '未知状态',
  21.     };
  22. }
复制代码
不用 PHP 8 的命名参数
  1. // 错误做法
  2. function createUser($name, $email, $age = null, $country = null) {
  3.     // 必须记住参数顺序
  4.     return new User($name, $email, null, 'US');
  5. }
  6. // 正确做法
  7. function createUser(
  8.     string $name,
  9.     string $email,
  10.     ?int $age = null,
  11.     ?string $country = null
  12. ): User {
  13.     return new User(
  14.         name: $name,
  15.         email: $email,
  16.         age: $age,
  17.         country: $country ?? 'US'
  18.     );
  19. }
复制代码
验证邮箱等数据时方法不对
  1. // 错误做法
  2. function validateEmail($email) {
  3.     return strpos($email, '@') !== false;
  4. }
  5. // 正确做法
  6. function validateEmail(string $email): bool {
  7.     return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
  8. }
复制代码
处理大文件时一次性读入内存
  1. // 错误做法
  2. function processLargeFile($filename) {
  3.     $content = file_get_contents($filename); // 将整个文件加载到内存
  4.     $lines = explode("\n", $content);
  5.     foreach ($lines as $line) {
  6.         // 处理每行
  7.     }
  8. }
  9. // 正确做法
  10. function processLargeFile(string $filename): void {
  11.     $handle = fopen($filename, 'r');
  12.     while (($line = fgets($handle)) !== false) {
  13.         // 处理每行
  14.     }
  15.     fclose($handle);
  16. }
复制代码
在类里直接 new 对象,不用依赖注入
  1. // 错误做法
  2. class UserService {
  3.     private $db;
  4.     public function __construct() {
  5.         $this->db = new Database(); // 硬编码依赖
  6.     }
  7. }
  8. // 正确做法
  9. class UserService {
  10.     public function __construct(
  11.         private readonly DatabaseInterface $db
  12.     ) {}
  13. }
复制代码
自定义异常不定义错误码
  1. // 错误做法
  2. class CustomException extends Exception {
  3.     public function __construct($message) {
  4.         parent::__construct($message);
  5.     }
  6. }
  7. // 正确做法
  8. class CustomException extends Exception {
  9.     public const INVALID_INPUT = 1001;
  10.     public const DATABASE_ERROR = 1002;
  11.     public const API_ERROR = 1003;
  12.     public function __construct(
  13.         string $message,
  14.         int $code = self::INVALID_INPUT,
  15.         ?Throwable $previous = null
  16.     ) {
  17.         parent::__construct($message, $code, $previous);
  18.     }
  19. }
复制代码
不用提前返回,嵌套太深
  1. // 错误做法
  2. function processUser($user) {
  3.     if ($user !== null) {
  4.         if ($user->isActive()) {
  5.             if ($user->hasPermission('admin')) {
  6.                 // 执行操作
  7.                 return true;
  8.             }
  9.         }
  10.     }
  11.     return false;
  12. }
  13. // 正确做法
  14. function processUser(?User $user): bool {
  15.     if ($user === null) {
  16.         return false;
  17.     }
  18.     if (!$user->isActive()) {
  19.         return false;
  20.     }
  21.     if (!$user->hasPermission('admin')) {
  22.         return false;
  23.     }
  24.     // 执行操作
  25.     return true;
  26. }
复制代码
数组初始化为 null,后面可能出错
  1. // 错误做法
  2. $items = null;
  3. if (someCondition()) {
  4.     $items = [];
  5. }
  6. // 正确做法
  7. $items = [];
  8. if (someCondition()) {
  9.     // 填充数组
  10. }
复制代码
日志记录信息不够详细
  1. // 错误做法
  2. function processPayment($amount) {
  3.     try {
  4.         // 处理支付
  5.     } catch (Exception $e) {
  6.         error_log('支付失败');
  7.     }
  8. }
  9. // 正确做法
  10. function processPayment(float $amount): void {
  11.     try {
  12.         // 处理支付
  13.     } catch (PaymentException $e) {
  14.         $context = [
  15.             'amount' => $amount,
  16.             'error' => $e->getMessage(),
  17.             'trace' => $e->getTraceAsString(),
  18.             'timestamp' => date('Y-m-d H:i:s')
  19.         ];
  20.         $this->logger->error('支付处理失败', $context);
  21.         throw $e;
  22.     }
  23. }
复制代码
不用服务容器,手动管理依赖
  1. // 错误做法
  2. class UserController {
  3.     private UserService $userService;
  4.     private Logger $logger;
  5.     public function __construct() {
  6.         $this->userService = new UserService(new Database());
  7.         $this->logger = new Logger();
  8.     }
  9. }
  10. // 正确做法
  11. class Container {
  12.     private array $services = [];
  13.     private array $factories = [];
  14.     public function register(string $id, callable $factory): void {
  15.         $this->factories[$id] = $factory;
  16.     }
  17.     public function get(string $id): object {
  18.         if (!isset($this->services[$id])) {
  19.             if (!isset($this->factories[$id])) {
  20.                 throw new ServiceNotFoundException($id);
  21.             }
  22.             $this->services[$id] = $this->factories[$id]();
  23.         }
  24.         return $this->services[$id];
  25.     }
  26. }
  27. class UserController {
  28.     public function __construct(
  29.         private readonly UserService $userService,
  30.         private readonly LoggerInterface $logger
  31.     ) {}
  32. }
复制代码
用 MD5 等弱算法存储密码
  1. // 错误做法
  2. function setPassword($password) {
  3.     $this->password = md5($password); // 绝不要用 MD5 处理密码
  4. }
  5. // 正确做法
  6. function setPassword(string $password): void {
  7.     $this->password = password_hash(
  8.         $password,
  9.         PASSWORD_DEFAULT,
  10.         ['cost' => 12]
  11.     );
  12. }
复制代码
总结

写好 PHP 代码,关键在于细节和对新特性的掌握。避开这些常见的坑,你的代码会更好维护、更安全、性能也更好。
几个要点:

  • 用严格类型,给函数加上类型声明
  • PHP 8 的新特性很好用,别浪费了
  • 安全问题不能马虎,SQL 注入、密码存储都要注意
  • 性能优化要有针对性,别过早优化
  • 代码要写得清晰,别人能看懂
  • SOLID 原则还是很有用的
  • 错误处理要到位,别让程序莫名其妙挂掉
  • 日志要记得详细点,出问题好排查
  • 代码要能测试,不然改起来心里没底
  • PHP 更新很快,要跟上节奏
推荐资源


  • PHP 官方文档 - 最权威的参考
  • PHP 标准建议 (PSR) - 社区规范
  • PHP The Right Way - 最佳实践合集
  • 《现代 PHP》等书籍
  • PHP 安全指南 - 安全编程必读

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册