PHP基础教程(48)PHP编码规范:PHP编码防秃指南:规范代码让你少加班,同事不再想打你

一、为啥要学编码规范?—— 先救救你的头发和同事关系

如果你写过这样的代码:

function doIt($a,$b){if($a>$b){return $a+$b;}else{return $a-$b;}}

恭喜你,你已经成为“团队最想暗杀程序员排行榜”的种子选手!

不规范代码的三大罪状:

  1. 读代码像破译甲骨文
    变量名 $a$tmp1$data2……请问这是要给变量举办“最无聊命名大赛”吗?一个月后你自己都看不懂,何况接手的新人(可能正在磨刀)。
  2. 调试时间比写代码长10倍
    缩进乱如麻花,ifelse 隔了五行屏幕远,找bug时眼神得像玩“大家来找茬”。深夜加班改bug?活该,谁让你写代码像草书!
  3. 团队协作变成“代码打架”
    你写 snake_case 函数名,他用 camelCase,另一个用 匈牙利命名法……合并代码时Git冲突多到像修罗场,最后只能靠吼解决:“你这写的啥玩意儿?!”

说白了,编码规范就是程序员世界的交通规则——没红绿灯的路口,车撞人飞;没规范的代码,人秃心碎。


二、PHP编码规范核心六条“保命法则”

法则1:命名要像给宠物起名,别瞎应付!
  • 变量/函数名:用蛇形命名(snake_case)还是驼峰(camelCase)?
    PHP官方推荐:变量、函数、方法用 snake_case,类名用 大驼峰(StudlyCase)
// 坏例子:混搭风,逼死强迫症
$UserName = "张三";
function GetData() {}
class user_model {}

// 好例子:统一才是王道
$user_name = "张三";
function get_data() {}
class UserModel {}
  • 起名要有“人话感”,别当谜语人
// 坏例子:这货是干啥的?
$tmp = query($sql); // tmp是临时文件?临时变量?临时工?
function proc() {}   // 处理?进程?切土豆?

// 好例子:看名字就懂
$user_list = fetch_users_from_database();
function calculate_order_total() {}
法则2:缩进和大括号——代码的“发型”不能乱

PHP推荐用 4个空格缩进(不许用Tab!因为不同编辑器显示可能不同),大括号换行放还是行尾放?看例子:

// 坏例子:括号乱飞,眼已花
if ($condition){
    echo "yes";}
else {echo "no";}

// 好例子:清爽如男团发型
if ($condition) {
    echo "yes";
} else {
    echo "no";
}
法则3:注释不是日记,少写废话多写“为什么”
// 坏例子:废话注释
$count = 0; // 设置count为0

// 好例子:解释复杂逻辑的意图
// 因为API限制每秒10次请求,需要延迟避免被封
sleep(0.1);
法则4:行长限制——别让代码变成“横屏马拉松”

单行建议不超过80字符,超了就换行:

// 坏例子:需要左右滚动屏幕才能看完
$result = $this->some_really_long_method_name($param1, $param2, $param3, $param4);

// 好例子:拆行更易读
$result = $this->some_really_long_method_name(
    $param1, 
    $param2, 
    $param3, 
    $param4
);
法则5:文件结构像衣柜,分门别类别乱塞
  • 一个类一个文件,文件名和类名一致(如 UserService.phpUserService 类)
  • 用命名空间(Namespace)做“文件夹划分”:
// 坏例子:所有类扔全局,名字冲突预警!
class Logger {}
class User {}

// 好例子:命名空间隔离
namespace App\Services;
class Logger {}

namespace App\Models;
class User {}
法则6:安全与性能——别让代码成黑客后门
  • 永远不要相信用户输入!SQL注入警告:
// 坏例子:黑客狂喜
$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];

// 好例子:参数绑定保平安
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
  • 及时关数据库连接、用缓存减少重复查询……(细节看后续示例)

三、完整示例:一个规范的用户注册模块

下面是一个符合PSR标准(PHP官方推荐规范)的迷你项目,包含用户注册、验证和日志记录:

项目结构
demo_project/
├── app/
│   ├── Models/
│   │   └── User.php
│   ├── Services/
│   │   ├── UserService.php
│   │   └── LoggerService.php
│   └── Utils/
│       └── Validator.php
├── config/
│   └── database.php
└── public/
    └── index.php
代码逐文件解析

1. 数据库配置(config/database.php)

<?php
// 配置用常量定义,大写+下划线
define('DB_HOST', 'localhost');
define('DB_NAME', 'test_db');
define('DB_USER', 'root');
define('DB_PASS', 'password');

// 返回PDO连接,确保错误模式为异常(方便调试)
function get_db_connection()
{
    try {
        $dsn = sprintf('mysql:host=%s;dbname=%s;charset=utf8', DB_HOST, DB_NAME);
        $pdo = new PDO($dsn, DB_USER, DB_PASS);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $pdo;
    } catch (PDOException $e) {
        // 记录日志而不是直接暴露错误给用户
        error_log("数据库连接失败: " . $e->getMessage());
        throw new Exception("系统维护中,请稍后重试");
    }
}

2. 用户模型(app/Models/User.php)

<?php
namespace App\Models;

use PDO;
use Exception;

class User
{
    private $pdo;
    
    // 依赖注入连接,方便测试
    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }
    
    // 方法名清晰描述行为
    public function create_user(array $user_data): int
    {
        // 参数验证
        if (empty($user_data['email']) || empty($user_data['password'])) {
            throw new Exception("邮箱和密码必填");
        }
        
        // SQL用参数绑定防注入
        $sql = "INSERT INTO users (email, password_hash, created_at) 
                VALUES (:email, :password_hash, NOW())";
        $stmt = $this->pdo->prepare($sql);
        
        // 密码哈希存储(千万别明文!)
        $hashed_password = password_hash($user_data['password'], PASSWORD_DEFAULT);
        
        $stmt->execute([
            ':email' => $user_data['email'],
            ':password_hash' => $hashed_password
        ]);
        
        return (int)$this->pdo->lastInsertId();
    }
    
    // 查找用户:返回类型声明(PHP7+特性)
    public function find_user_by_email(string $email): ?array
    {
        $stmt = $this->pdo->prepare("SELECT * FROM users WHERE email = :email");
        $stmt->execute([':email' => $email]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $result ?: null; // 清晰的三元表达式
    }
}

3. 日志服务(app/Services/LoggerService.php)

<?php
namespace App\Services;

class LoggerService
{
    // 用常量定义日志级别
    const LEVEL_ERROR = 'ERROR';
    const LEVEL_INFO  = 'INFO';
    
    private $log_file;
    
    public function __construct(string $log_file_path)
    {
        // 确保日志目录存在
        $dir = dirname($log_file_path);
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }
        $this->log_file = $log_file_path;
    }
    
    // 格式化日志信息,包含时间戳和级别
    public function log(string $message, string $level = self::LEVEL_INFO): void
    {
        $timestamp = date('Y-m-d H:i:s');
        $log_entry = sprintf("[%s] %s: %s\n", $timestamp, $level, $message);
        
        // 文件追加写入,LOCK_EX防止并发写入混乱
        file_put_contents($this->log_file, $log_entry, FILE_APPEND | LOCK_EX);
    }
}

4. 主入口文件(public/index.php)

<?php
// 统一入口,初始化设置
error_reporting(E_ALL);
ini_set('display_errors', '0'); // 生产环境不显示错误给用户
ini_set('log_errors', '1');

// 自动加载(简单版示例,实际建议用Composer)
spl_autoload_register(function ($class_name) {
    $file = __DIR__ . '/../app/' . str_replace('\\', '/', $class_name) . '.php';
    if (file_exists($file)) {
        require_once $file;
    }
});

// 处理用户注册请求
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
    try {
        // 1. 获取配置
        require_once __DIR__ . '/../config/database.php';
        
        // 2. 初始化服务和模型
        $pdo = get_db_connection();
        $user_model = new App\Models\User($pdo);
        $logger = new App\Services\LoggerService(__DIR__ . '/../logs/app.log');
        
        // 3. 业务逻辑
        if ($_POST['action'] === 'register') {
            $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
            $password = $_POST['password'] ?? '';
            
            if (!$email || strlen($password) < 6) {
                throw new Exception("邮箱无效或密码太短");
            }
            
            // 检查用户是否已存在
            if ($user_model->find_user_by_email($email)) {
                throw new Exception("该邮箱已注册");
            }
            
            // 创建用户
            $user_id = $user_model->create_user([
                'email' => $email,
                'password' => $password
            ]);
            
            // 记录成功日志
            $logger->log("用户注册成功: ID={$user_id}, Email={$email}");
            
            echo json_encode([
                'success' => true,
                'message' => '注册成功,请登录'
            ]);
        }
    } catch (Exception $e) {
        // 统一错误处理
        if (isset($logger)) {
            $logger->log("注册失败: " . $e->getMessage(), LoggerService::LEVEL_ERROR);
        }
        
        http_response_code(400);
        echo json_encode([
            'success' => false,
            'message' => $e->getMessage()
        ]);
    }
} else {
    // 显示注册表单(前端部分简化)
    ?>
    <!DOCTYPE html>
    <html>
    <head>
        <title>用户注册示例</title>
        <style>
            body { font-family: Arial; max-width: 400px; margin: 50px auto; }
            input { display: block; margin: 10px 0; padding: 8px; width: 100%; }
            button { background: #007bff; color: white; padding: 10px; border: none; }
        </style>
    </head>
    <body>
        <h2>注册体验规范代码</h2>
        <form method="POST">
            <input type="email" name="email" placeholder="邮箱" required>
            <input type="password" name="password" placeholder="密码(至少6位)" required>
            <input type="hidden" name="action" value="register">
            <button type="submit">提交</button>
        </form>
        <script>
            // 简单前端验证
            document.querySelector('form').addEventListener('submit', function(e) {
                const password = this.querySelector('[name="password"]').value;
                if (password.length < 6) {
                    alert('密码太短啦!');
                    e.preventDefault();
                }
            });
        </script>
    </body>
    </html>
    <?php
}

四、规范带来的实际好处:算笔经济账

假设你团队有5个PHP程序员:

  • 不规范时:每人每天多花1小时读/改混乱代码,每月多加班20小时,时薪100元 → 每月浪费5×20×100=10,000元
  • 规范后:代码可读性提升,新人上手快,合并冲突减少 → 省下的时间起码价值8,000元/月

更重要的是:代码质量高,线上bug少,半夜报警少,头发掉得少,老婆吵架少!


五、快速上手指南:工具推荐

  1. PHP_CodeSniffer:自动检查代码规范
composer require squizlabs/php_codesniffer
phpcs --standard=PSR12 app/
  1. PHP-CS-Fixer:自动修复不规范代码
composer require friendsofphp/php-cs-fixer
php-cs-fixer fix app/
  1. IDE配置
    • PHPStorm:开启PSR1/PSR2检查
    • VSCode:安装PHP Intelephense插件

最后说句大实话

编码规范就像刷牙——开始时觉得麻烦,习惯了就自然。不规范的代码短期内似乎写得快,但长期看是在给自己挖坑,迟早要跪着填。

记住:好程序员不止让代码能跑,还要让代码能“活”——活得久、活得稳、活得让别人接手时不想打你。

(完整示例代码已测试可运行,GitHub仓库地址私信我获取,避免广告嫌疑😂)


附录:常见QA
Q:规范太多记不住怎么办?
A:用工具自动检查!先掌握最核心的命名、缩进、注释三条,其他慢慢养成习惯。

Q:老项目代码一团乱,要不要重写?
A:别!用“逐步重构法”,新代码按规范写,旧代码在修改时顺手整理,像打扫房间一样慢慢来。

Q:团队有人不遵守怎么办?
A:代码审查时“温柔拒绝合并”,附上本文链接(暗示他该学习了😉)。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值