PHP 项目实现"人盯人防守成功率"统计
你需要明确一下需求,我先给你一个通用的实现方案和关键代码示例,因为"人盯人防守成功率"在篮球/足球统计中定义不同,我按篮球场景来写。

先明确业务定义
"人盯人防守成功率"通常指:
成功率 = 成功防守回合数 / 总盯人防守回合数 × 100%
什么算"成功"? 常见判定:
- 对手未得分
- 对手失误
- 对手投篮不中
- 造成进攻犯规
什么算"失败"?
- 对手得分
- 被突破导致失分
- 防守犯规送罚球
数据库设计
-- 球员表
CREATE TABLE players (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
team VARCHAR(50)
);
-- 防守回合记录表
CREATE TABLE defense_records (
id INT PRIMARY KEY AUTO_INCREMENT,
player_id INT, -- 防守人
opponent_id INT, -- 被防守人
match_id INT, -- 比赛ID
defense_type ENUM('man','zone') DEFAULT 'man', -- 防守类型
result ENUM('success','fail') NOT NULL, -- 结果
reason VARCHAR(50), -- 原因: steal/miss/score/foul...
quarter TINYINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (player_id) REFERENCES players(id)
);
核心 PHP 代码
配置 & 数据库连接 db.php
<?php
$pdo = new PDO('mysql:host=localhost;dbname=basketball;charset=utf8mb4',
'root', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
计算成功率的模型 DefenseStats.php
<?php
require 'db.php';
class DefenseStats
{
private PDO $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
/**
* 统计某个球员的人盯人防守成功率
*/
public function manToManRate(int $playerId, ?int $matchId = null): array
{
$sql = "SELECT
COUNT(*) AS total,
SUM(result = 'success') AS success,
SUM(result = 'fail') AS fail
FROM defense_records
WHERE player_id = :pid
AND defense_type = 'man'";
$params = ['pid' => $playerId];
if ($matchId !== null) {
$sql .= " AND match_id = :mid";
$params['mid'] = $matchId;
}
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
$row = $stmt->fetch();
$total = (int)$row['total'];
$success = (int)$row['success'];
$rate = $total > 0 ? round($success / $total * 100, 2) : 0.0;
return [
'player_id' => $playerId,
'total' => $total,
'success' => $success,
'fail' => (int)$row['fail'],
'rate' => $rate, // 百分比,例:73.21
];
}
/**
* 全队排行(按成功率降序)
*/
public function teamRanking(int $matchId): array
{
$sql = "SELECT p.id, p.name,
COUNT(*) AS total,
SUM(d.result='success') AS success,
ROUND(SUM(d.result='success') / COUNT(*) * 100, 2) AS rate
FROM defense_records d
JOIN players p ON p.id = d.player_id
WHERE d.defense_type = 'man' AND d.match_id = :mid
GROUP BY p.id, p.name
HAVING total >= 5
ORDER BY rate DESC";
$stmt = $this->pdo->prepare($sql);
$stmt->execute(['mid' => $matchId]);
return $stmt->fetchAll();
}
}
调用示例 index.php
<?php
require 'DefenseStats.php';
$stats = new DefenseStats($pdo);
// 单个球员本赛季人盯人成功率
$result = $stats->manToManRate(playerId: 7);
printf("球员%d:%d/%d,成功率 %.2f%%\n",
$result['player_id'],
$result['success'],
$result['total'],
$result['rate']
);
// 本场比赛全队排行
foreach ($stats->teamRanking(matchId: 101) as $r) {
printf("%-10s %3d/%3d %.2f%%\n",
$r['name'], $r['success'], $r['total'], $r['rate']);
}
输出示例:
球员7:11/15,成功率 73.33%
张三 11/15 73.33%
李四 9/12 75.00%
王五 4/10 40.00%
进阶:加入"加权成功率"
不同防守结果价值不同,可以加权:
// 权重:抢断 1.2,逼迫失误 1.1,投篮不中 1.0,得分 -1.0,犯规 -0.8
$weights = [
'steal' => 1.2,
'turnover' => 1.1,
'miss' => 1.0,
'score' => -1.0,
'foul' => -0.8,
];
$sql = "SELECT SUM(CASE reason
WHEN 'steal' THEN 1.2
WHEN 'turnover' THEN 1.1
WHEN 'miss' THEN 1.0
WHEN 'score' THEN -1.0
WHEN 'foul' THEN -0.8
END) AS score,
COUNT(*) AS total
FROM defense_records
WHERE player_id = ? AND defense_type='man'";
常见坑提醒
| 问题 | 说明 |
|---|---|
| 除零错误 | total=0 时必须返回 0,不能直接除 |
| 样本太小 | 出场<5次不建议排名(用 HAVING total >= 5) |
| 换防归属 | 挡拆换防后,谁算防守人?建议记录表存"实际防守人" |
| 时间维度 | 是"本场"还是"赛季"?一定要在 SQL 里区分 match_id |
| 快攻/协防 | 是否算人盯人?最好和录像剪辑规则对齐 |
你能补充下具体场景吗?
- 是篮球还是足球?
- 有没有现成的数据表结构?
- 是要网页展示(配图表)还是接口返回 JSON?
告诉我这些,我可以给你贴合你项目的完整代码。