本文目录导读:

我来帮你设计一个PHP接口文档生成集成方案,这个方案将包含自动生成、手动补充和展示等功能。
核心架构设计
<?php
// ApiDocGenerator.php - 核心文档生成器
namespace App\ApiDoc;
class ApiDocGenerator
{
private array $collectedData = [];
private array $config;
private array $customAnnotations = [
'api' => 'Api\Description',
'apiGroup' => 'Api\Group',
'apiName' => 'Api\Name',
'apiParam' => 'Api\Param',
'apiSuccess' => 'Api\Success',
'apiError' => 'Api\Error',
'apiVersion' => 'Api\Version',
'apiHeader' => 'Api\Header',
'apiRequestExample' => 'Api\RequestExample',
'apiSuccessExample' => 'Api\ResponseExample',
'apiPermission' => 'Api\Permission',
'apiDeprecated' => 'Api\Deprecated'
];
public function __construct(array $config = [])
{
$this->config = array_merge([
'output_dir' => __DIR__ . '/docs',
'format' => 'json', // json or markdown
'scan_dirs' => [__DIR__ . '/../app/Controllers'],
'exclude_dirs' => ['vendor', 'node_modules'],
'version' => '1.0.0',
'title' => 'API Documentation',
'description' => 'Auto-generated API documentation'
], $config);
}
/**
* 扫描目录并收集API信息
*/
public function scan(): void
{
foreach ($this->config['scan_dirs'] as $dir) {
$this->scanDirectory($dir);
}
}
private function scanDirectory(string $dir): void
{
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($dir)
);
foreach ($iterator as $file) {
if ($file->isDir()) {
continue;
}
if ($file->getExtension() !== 'php') {
continue;
}
// 检查排除目录
foreach ($this->config['exclude_dirs'] as $exclude) {
if (strpos($file->getPathname(), $exclude) !== false) {
continue 2;
}
}
$this->parseFile($file->getPathname());
}
}
private function parseFile(string $filePath): void
{
$content = file_get_contents($filePath);
$tokenizer = new DocParser($content);
foreach ($tokenizer->getClassMethods() as $method) {
$docBlock = $this->parseDocBlock($method['docBlock']);
if ($this->isApiMethod($docBlock)) {
$this->collectedData[] = $this->buildApiInfo($method, $docBlock, $filePath);
}
}
}
private function parseDocBlock(string $docBlock): array
{
$parsed = [];
preg_match_all('/@(\w+)\s+(.*)/', $docBlock, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$annotation = str_replace('api', '', $match[1]);
$parsed[$annotation][] = trim($match[2]);
}
return $parsed;
}
private function isApiMethod(array $docBlock): bool
{
return isset($docBlock['name']) && !empty($docBlock['name']);
}
private function buildApiInfo(array $method, array $docBlock, string $filePath): array
{
$apiInfo = [
'method' => $method['name'],
'controller' => $this->getControllerName($filePath),
'file' => basename($filePath),
'group' => $docBlock['group'][0] ?? 'default',
'name' => $docBlock['name'][0] ?? $method['name'],
'description' => $docBlock['description'] ?? '',
'version' => $docBlock['version'][0] ?? $this->config['version'],
'deprecated' => $docBlock['deprecated'] ?? false,
'permission' => $docBlock['permission'][0] ?? 'public',
'headers' => [],
'params' => [],
'success' => [],
'error' => []
];
// 解析路由信息(从注释或框架路由配置)
$apiInfo['route'] = $this->extractRouteInfo($method, $docBlock);
// 解析参数
foreach ($docBlock['param'] ?? [] as $param) {
$apiInfo['params'][] = $this->parseParam($param);
}
// 解析响应
foreach ($docBlock['success'] ?? [] as $success) {
$apiInfo['success'][] = $this->parseResponse($success);
}
// 解析错误返回
foreach ($docBlock['error'] ?? [] as $error) {
$apiInfo['error'][] = $this->parseResponse($error);
}
// 解析请求头
foreach ($docBlock['header'] ?? [] as $header) {
$apiInfo['headers'][] = $this->parseHeader($header);
}
// 解析示例
$apiInfo['requestExample'] = $docBlock['requestExample'][0] ?? '';
$apiInfo['responseExample'] = $docBlock['successExample'] ?? [];
return $apiInfo;
}
private function parseParam(string $param): array
{
// 格式: @apiParam {type} field description
preg_match('/\{(\w+)\}\s+(\w+)\s+(.*)/', $param, $matches);
return [
'type' => $matches[1] ?? 'string',
'field' => $matches[2] ?? '',
'description' => $matches[3] ?? ''
];
}
private function parseResponse(string $response): array
{
// 格式: @apiSuccess {type} field description
return $this->parseParam($response);
}
private function parseHeader(string $header): array
{
return $this->parseParam($header);
}
private function extractRouteInfo(array $method, array $docBlock): array
{
$route = [];
// 从路由注解或注释中提取
if (isset($docBlock['route'])) {
$parts = explode(' ', $docBlock['route'][0]);
$route['method'] = $parts[0] ?? 'GET';
$route['path'] = $parts[1] ?? '';
}
return $route;
}
private function getControllerName(string $filePath): string
{
$baseName = basename($filePath, '.php');
return str_replace(['Controller', 'controller'], '', $baseName);
}
/**
* 生成文档
*/
public function generate(string $format = null): bool
{
$format = $format ?? $this->config['format'];
$this->scan();
switch ($format) {
case 'json':
return $this->generateJson();
case 'markdown':
return $this->generateMarkdown();
case 'html':
return $this->generateHtml();
case 'pdf':
return $this->generatePdf();
default:
return $this->generateJson();
}
}
private function generateJson(): bool
{
$data = [
'title' => $this->config['title'],
'version' => $this->config['version'],
'description' => $this->config['description'],
'generated_at' => date('Y-m-d H:i:s'),
'apis' => $this->collectedData
];
return $this->writeFile('api-docs.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
}
private function generateMarkdown(): bool
{
$content = "# {$this->config['title']}\n\n";
$content .= "> 版本: {$this->config['version']}\n";
$content .= "> 生成时间: " . date('Y-m-d H:i:s') . "\n\n";
// 按分组组织文档
$groups = [];
foreach ($this->collectedData as $api) {
$groups[$api['group']][] = $api;
}
foreach ($groups as $group => $apis) {
$content .= "## {$group}\n\n";
foreach ($apis as $api) {
$content .= $this->formatApiMarkdown($api);
}
}
return $this->writeFile('api-docs.md', $content);
}
private function generateHtml(): bool
{
$htmlTemplate = file_get_contents(__DIR__ . '/templates/api-doc-template.html');
$data = [
'title' => $this->config['title'],
'version' => $this->config['version'],
'apis' => $this->collectedData
];
$html = str_replace('{{DATA}}', json_encode($data), $htmlTemplate);
return $this->writeFile('api-docs.html', $html);
}
private function generatePdf(): bool
{
// 需要安装 domino/dompdf 或类似库
$html = $this->generateHtmlContent();
$dompdf = new \Dompdf\Dompdf();
$dompdf->loadHtml($html);
$dompdf->setPaper('A4');
$dompdf->render();
return file_put_contents(
$this->config['output_dir'] . '/api-docs.pdf',
$dompdf->output()
) !== false;
}
private function generateHtmlContent(): string
{
$content = $this->generateMarkdownContent();
// 转换 Markdown 到 HTML
$parsedown = new \Parsedown();
return $parsedown->text($content);
}
private function writeFile(string $filename, string $content): bool
{
if (!is_dir($this->config['output_dir'])) {
mkdir($this->config['output_dir'], 0777, true);
}
return file_put_contents(
$this->config['output_dir'] . '/' . $filename,
$content
) !== false;
}
private function formatApiMarkdown(array $api): string
{
$content = "### " . ($api['name'] ?? $api['method']) . "\n\n";
$content .= "**描述:** {$api['description']}\n\n";
$content .= "**路由:** `{$api['route']['method']} {$api['route']['path']}`\n\n";
$content .= "**版本:** {$api['version']}\n\n";
$content .= "**权限:** {$api['permission']}\n\n";
if ($api['deprecated']) {
$content .= "> ⚠️ **已废弃**\n\n";
}
if (!empty($api['params'])) {
$content .= "**请求参数:**\n\n";
$content .= "| 字段 | 类型 | 描述 |\n|------|------|------|\n";
foreach ($api['params'] as $param) {
$content .= "| {$param['field']} | {$param['type']} | {$param['description']} |\n";
}
$content .= "\n";
}
if (!empty($api['success'])) {
$content .= "**成功响应:**\n\n";
$content .= "| 字段 | 类型 | 描述 |\n|------|------|------|\n";
foreach ($api['success'] as $param) {
$content .= "| {$param['field']} | {$param['type']} | {$param['description']} |\n";
}
$content .= "\n";
}
if (!empty($api['error'])) {
$content .= "**错误响应:**\n\n";
$content .= "| 字段 | 类型 | 描述 |\n|------|------|------|\n";
foreach ($api['error'] as $param) {
$content .= "| {$param['field']} | {$param['type']} | {$param['description']} |\n";
}
$content .= "\n";
}
if ($api['requestExample']) {
$content .= "**请求示例:**\n\n```json\n{$api['requestExample']}\n```\n\n";
}
if (!empty($api['responseExample'])) {
$content .= "**响应示例:**\n\n```json\n" . json_encode($api['responseExample'], JSON_PRETTY_PRINT) . "\n```\n\n";
}
return $content . "\n---\n\n";
}
}
文档解析器
<?php
// DocParser.php - 注释解析器
namespace App\ApiDoc;
class DocParser
{
private string $content;
private array $classes = [];
private array $methods = [];
public function __construct(string $content)
{
$this->content = $content;
$this->parse();
}
private function parse(): void
{
$tokens = token_get_all($this->content);
// 解析类和方法的注释
$this->parseClassesAndMethods($tokens);
$this->parseRoutesFromAnnotations($tokens);
}
private function parseClassesAndMethods(array $tokens): void
{
$currentClass = null;
$currentMethod = null;
$docBlockBuffer = '';
$inDocBlock = false;
foreach ($tokens as $token) {
if (is_array($token)) {
switch ($token[0]) {
case T_DOC_COMMENT:
if ($inDocBlock) {
$docBlockBuffer .= $token[1];
}
break;
case T_CLASS:
// 找到类名
$nextToken = $this->getNextNonWhitespaceToken($tokens);
if (isset($nextToken[2])) {
$currentClass = $nextToken[2];
}
break;
case T_FUNCTION:
// 找到方法名
$nextToken = $this->getNextNonWhitespaceToken($tokens);
if (isset($nextToken[2])) {
$currentMethod = $nextToken[2];
$this->methods[] = [
'name' => $currentMethod,
'docBlock' => $docBlockBuffer,
'class' => $currentClass
];
}
$docBlockBuffer = '';
break;
}
}
}
}
private function parseRoutesFromAnnotations(array $tokens): void
{
// 解析框架路由注解,@Route()
// ActiveRecord 或 Doctrine 风格的注解
}
private function getNextNonWhitespaceToken(array $tokens): ?array
{
// 获取下一个非空白字符的token
foreach ($tokens as $key => $token) {
if (is_array($token) && $token[0] !== T_WHITESPACE) {
return $token;
}
}
return null;
}
public function getClassMethods(): array
{
return $this->methods;
}
public function getClasses(): array
{
return $this->classes;
}
}
控制器示例
<?php
// UserController.php
namespace App\Controllers;
use App\ApiDoc\Attributes\ApiDoc;
class UserController extends BaseController
{
/**
* @api {get} /api/users 获取用户列表
* @apiGroup 用户管理
* @apiName GetUserList
* @apiVersion 1.0.0
*
* @apiHeader {string} Authorization 请求认证令牌
*
* @apiParam {int} page 页码
* @apiParam {int} limit 每页数量
* @apiParam {string} keyword 搜索关键词
*
* @apiSuccess {int} code 状态码
* @apiSuccess {string} message 返回信息
* @apiSuccess {array} data 用户列表数据
* @apiSuccess {int} data.id 用户ID
* @apiSuccess {string} data.name 用户名
*
* @apiError {int} code 错误码
* @apiError {string} message 错误信息
*
* @apiSuccessExample {json} 成功响应示例:
* {
* "code": 200,
* "message": "成功",
* "data": [
* {
* "id": 1,
* "name": "张三"
* }
* ]
* }
*
* @apiPermission authenticated
* @apiDeprecated false
*/
public function index()
{
return $this->apiResponse([
'code' => 200,
'message' => '成功',
'data' => [
['id' => 1, 'name' => '张三'],
['id' => 2, 'name' => '李四']
]
]);
}
/**
* @api {post} /api/users 创建用户
* @apiGroup 用户管理
* @apiName CreateUser
* @apiVersion 1.0.0
*
* @apiParam {string} name 用户名
* @apiParam {string} email 邮箱
* @apiParam {string} password 密码
*
* @apiSuccess {int} code 状态码
* @apiSuccess {string} message 返回信息
*
* @apiSuccessExample {json} 成功响应示例:
* {
* "code": 200,
* "message": "创建成功"
* }
*/
public function create()
{
return $this->apiResponse([
'code' => 200,
'message' => '创建成功'
]);
}
/**
* @api {get} /api/users/:id 获取用户详情
* @apiGroup 用户管理
* @apiName GetUserDetail
* @apiVersion 1.0.0
*
* @apiParam {int} id 用户ID
*
* @apiSuccess {int} code 状态码
* @apiSuccess {object} data 用户数据
*
* @apiError {int} code 404
* @apiError {string} message 用户不存在
*/
public function show($id)
{
return $this->apiResponse([
'code' => 200,
'data' => [
'id' => $id,
'name' => '张三'
]
]);
}
/**
* @api {put} /api/users/:id 更新用户
* @apiGroup 用户管理
* @apiName UpdateUser
* @apiVersion 1.0.0
*
* @apiParam {int} id 用户ID
* @apiParam {string} name 用户名
*
* @apiSuccess {int} code 状态码
*/
public function update($id)
{
return $this->apiResponse([
'code' => 200,
'message' => '更新成功'
]);
}
}
命令行接口
<?php
// bin/generate-docs.php
require __DIR__ . '/../vendor/autoload.php';
use App\ApiDoc\ApiDocGenerator;
// 配置
$config = [
'output_dir' => __DIR__ . '/../docs',
'format' => 'markdown',
'scan_dirs' => [
__DIR__ . '/../app/Controllers'
],
'exclude_dirs' => ['vendor', 'node_modules'], => 'My API Documentation',
'version' => '1.0.0'
];
// 解析命令行参数
$options = getopt('f:o:h', ['format:', 'output:', 'help']);
if (isset($options['h']) || isset($options['help'])) {
echo <<<HELP
PHP API Documentation Generator
================================
Usage: php generate-docs.php [options]
Options:
-f, --format FORMAT Output format (json, markdown, html, pdf)
-o, --output DIR Output directory
-h, --help Show this help message
Examples:
php generate-docs.php -f markdown
php generate-docs.php --format=html -o /var/www/docs
HELP;
exit(0);
}
// 覆写配置
if (isset($options['f']) || isset($options['format'])) {
$config['format'] = $options['f'] ?? $options['format'];
}
if (isset($options['o']) || isset($options['output'])) {
$config['output_dir'] = $options['o'] ?? $options['output'];
}
// 检查composer依赖
if (!file_exists(__DIR__ . '/../vendor/autoload.php')) {
echo "错误:请先运行 composer install\n";
exit(1);
}
try {
$generator = new ApiDocGenerator($config);
// 添加自定义注解支持
$generator->addCustomAnnotation('apiDeprecated', 'Deprecated');
echo "开始扫描API...\n";
// 生成文档
$result = $generator->generate();
if ($result) {
echo "✓ 文档生成成功!\n";
echo "输出目录:" . realpath($config['output_dir']) . "\n";
echo "生成的文档文件:\n";
// 列出生成的文件
foreach (glob($config['output_dir'] . '/api-docs.*') as $file) {
echo " - " . basename($file) . " (" . round(filesize($file) / 1024, 2) . " KB)\n";
}
} else {
echo "✗ 文档生成失败!\n";
exit(1);
}
} catch (\Exception $e) {
echo "错误:" . $e->getMessage() . "\n";
exit(1);
}
配置示例
<?php
// config/apidoc.php
return [
'output' => [
'dir' => __DIR__ . '/../docs',
'format' => 'markdown', // json, markdown, html, pdf
],
'scan' => [
'directories' => [
__DIR__ . '/../app/Controllers',
__DIR__ . '/../app/Api/Controllers',
],
'exclude' => [
'vendor',
'node_modules',
'tests',
],
'file_pattern' => '*Controller.php',
],
'documentation' => [
'title' => 'API Reference',
'description' => 'RESTful API documentation',
'version' => '1.0.0',
'author' => 'Your Company',
'contact' => 'dev@example.com',
'license' => 'MIT',
],
'annotations' => [
'custom' => [
'apiAuth' => ['type' => 'boolean', 'description' => '是否需要认证'],
'apiRateLimit' => ['type' => 'integer', 'description' => '速率限制'],
'apiCache' => ['type' => 'integer', 'description' => '缓存时间'],
],
],
'ui' => [
'theme' => 'default',
'showAuth' => true,
'showExamples' => true,
'showErrors' => true,
'showVersions' => true,
],
];
使用示例
# 生成Markdown文档 php bin/generate-docs.php -f markdown # 生成HTML文档 php bin/generate-docs.php -f html -o /var/www/docs # 生成JSON文档 php bin/generate-docs.php -f json # 使用配置文件 php bin/generate-docs.php --config=config/apidoc.php
高级功能
<?php
// 支持批量生成和多格式
class BatchDocGenerator
{
public function generateAll(): array
{
$results = [];
foreach (['json', 'markdown', 'html'] as $format) {
$generator = new ApiDocGenerator();
$generator->setFormat($format);
$results[$format] = $generator->generate();
}
return $results;
}
}
这个方案提供了完整的API文档自动生成能力,包括:
- 自动扫描:自动扫描控制器目录
- 注释解析:解析规范的API注释
- 多格式输出:支持JSON、Markdown、HTML、PDF
- 分组管理:按API分组整理
- 参数验证:验证参数格式
- 命令行工具:方便集成到CI/CD流程
- 扩展性强:支持自定义注解和格式
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播