控制器基础 #
一、控制器概述 #
1.1 什么是控制器 #
控制器是处理HTTP请求并返回响应的PHP类。每个控制器包含一个或多个动作方法,每个动作对应一个路由。
text
┌─────────────────────────────────────────────────────┐
│ 控制器工作流程 │
├─────────────────────────────────────────────────────┤
│ │
│ HTTP请求 │
│ ↓ │
│ 路由匹配 │
│ ↓ │
│ 控制器动作 │
│ ↓ │
│ 处理业务逻辑 │
│ ↓ │
│ 返回响应 │
│ │
└─────────────────────────────────────────────────────┘
1.2 控制器命名规范 #
text
控制器命名规范:
├── 类名: {Name}Controller
├── 文件: src/Controller/{Name}Controller.php
├── 方法: 动作方法名
└── 示例: UserController.php → class UserController
二、创建控制器 #
2.1 使用Maker命令 #
bash
# 创建控制器
php bin/console make:controller UserController
# 输出
created: src/Controller/UserController.php
created: templates/user/index.html.twig
2.2 手动创建控制器 #
php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class UserController extends AbstractController
{
#[Route('/user', name: 'app_user')]
public function index(): Response
{
return $this->render('user/index.html.twig', [
'controller_name' => 'UserController',
]);
}
}
2.3 控制器结构解析 #
php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class HomeController extends AbstractController
{
#[Route('/', name: 'app_home')]
public function index(): Response
{
return new Response('Hello World!');
}
}
| 组成部分 | 说明 |
|---|---|
| namespace | 命名空间,通常为App\Controller |
| extends AbstractController | 继承基础控制器,获取辅助方法 |
| #[Route] | 路由属性,定义URL映射 |
| public function | 动作方法,必须是public |
| Response | 返回类型,响应对象 |
三、动作方法 #
3.1 基本动作 #
php
<?php
class PageController extends AbstractController
{
#[Route('/', name: 'app_home')]
public function home(): Response
{
return new Response('Home Page');
}
#[Route('/about', name: 'app_about')]
public function about(): Response
{
return new Response('About Page');
}
#[Route('/contact', name: 'app_contact')]
public function contact(): Response
{
return new Response('Contact Page');
}
}
3.2 带参数的动作 #
php
<?php
class UserController extends AbstractController
{
#[Route('/user/{id}', name: 'app_user_show', requirements: ['id' => '\d+'])]
public function show(int $id): Response
{
return new Response("User ID: $id");
}
#[Route('/category/{category}/product/{productId}', name: 'app_product_show')]
public function productShow(string $category, int $productId): Response
{
return new Response("Category: $category, Product: $productId");
}
}
3.3 可选参数动作 #
php
<?php
class BlogController extends AbstractController
{
#[Route('/blog/{page}', name: 'app_blog_list', defaults: ['page' => 1])]
public function list(int $page): Response
{
return new Response("Blog Page: $page");
}
#[Route('/search/{keyword}', name: 'app_search', defaults: ['keyword' => null])]
public function search(?string $keyword): Response
{
return new Response("Search: " . ($keyword ?? 'all'));
}
}
四、返回响应 #
4.1 响应类型 #
php
<?php
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
class ResponseController extends AbstractController
{
#[Route('/text', name: 'app_text')]
public function text(): Response
{
return new Response('Plain Text Response');
}
#[Route('/html', name: 'app_html')]
public function html(): Response
{
return new Response('<h1>HTML Response</h1>');
}
#[Route('/json', name: 'app_json')]
public function json(): JsonResponse
{
return $this->json([
'status' => 'success',
'data' => ['id' => 1, 'name' => 'John'],
]);
}
#[Route('/redirect', name: 'app_redirect')]
public function redirect(): RedirectResponse
{
return $this->redirectToRoute('app_home');
}
#[Route('/template', name: 'app_template')]
public function template(): Response
{
return $this->render('page/template.html.twig', [
'title' => 'Template Page',
]);
}
}
4.2 响应状态码 #
php
<?php
class StatusController extends AbstractController
{
#[Route('/created', name: 'app_created')]
public function created(): Response
{
return new Response('Created', Response::HTTP_CREATED);
}
#[Route('/no-content', name: 'app_no_content')]
public function noContent(): Response
{
return new Response('', Response::HTTP_NO_CONTENT);
}
#[Route('/not-found', name: 'app_not_found')]
public function notFound(): Response
{
return new Response('Not Found', Response::HTTP_NOT_FOUND);
}
#[Route('/json-created', name: 'app_json_created')]
public function jsonCreated(): JsonResponse
{
return $this->json(
['status' => 'created'],
Response::HTTP_CREATED
);
}
}
4.3 响应头设置 #
php
<?php
class HeaderController extends AbstractController
{
#[Route('/custom-header', name: 'app_custom_header')]
public function customHeader(): Response
{
$response = new Response('Custom Header');
$response->headers->set('X-Custom-Header', 'value');
$response->headers->set('Cache-Control', 'no-cache');
return $response;
}
#[Route('/json-headers', name: 'app_json_headers')]
public function jsonHeaders(): JsonResponse
{
return $this->json(
['data' => 'value'],
Response::HTTP_OK,
['X-API-Version' => '1.0', 'X-Rate-Limit' => '100']
);
}
}
五、渲染模板 #
5.1 基本模板渲染 #
php
<?php
class TemplateController extends AbstractController
{
#[Route('/page', name: 'app_page')]
public function page(): Response
{
return $this->render('page/index.html.twig');
}
#[Route('/user/{id}', name: 'app_user_profile')]
public function profile(int $id): Response
{
return $this->render('user/profile.html.twig', [
'userId' => $id,
'userName' => 'User ' . $id,
]);
}
}
5.2 模板变量 #
php
<?php
class DashboardController extends AbstractController
{
#[Route('/dashboard', name: 'app_dashboard')]
public function index(): Response
{
$user = [
'id' => 1,
'name' => '张三',
'email' => 'zhangsan@example.com',
'roles' => ['ROLE_USER', 'ROLE_ADMIN'],
];
$stats = [
'totalUsers' => 1000,
'activeUsers' => 750,
'newUsers' => 50,
];
return $this->render('dashboard/index.html.twig', [
'user' => $user,
'stats' => $stats,
'title' => 'Dashboard',
'now' => new \DateTime(),
]);
}
}
5.3 Twig模板示例 #
twig
{# templates/dashboard/index.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}{{ title }}{% endblock %}
{% block body %}
<h1>{{ title }}</h1>
<div class="user-info">
<p>用户: {{ user.name }}</p>
<p>邮箱: {{ user.email }}</p>
<p>角色: {{ user.roles|join(', ') }}</p>
</div>
<div class="stats">
<h2>统计数据</h2>
<ul>
<li>总用户: {{ stats.totalUsers }}</li>
<li>活跃用户: {{ stats.activeUsers }}</li>
<li>新用户: {{ stats.newUsers }}</li>
</ul>
</div>
<p>当前时间: {{ now|date('Y-m-d H:i:s') }}</p>
{% endblock %}
六、重定向 #
6.1 路由重定向 #
php
<?php
class RedirectController extends AbstractController
{
#[Route('/old-home', name: 'app_old_home')]
public function oldHome(): Response
{
return $this->redirectToRoute('app_home');
}
#[Route('/old-user/{id}', name: 'app_old_user')]
public function oldUser(int $id): Response
{
return $this->redirectToRoute('app_user_show', ['id' => $id]);
}
#[Route('/redirect-permanent', name: 'app_redirect_permanent')]
public function redirectPermanent(): Response
{
return $this->redirectToRoute('app_home', [], 301);
}
}
6.2 外部重定向 #
php
<?php
class ExternalRedirectController extends AbstractController
{
#[Route('/symfony-docs', name: 'app_symfony_docs')]
public function symfonyDocs(): Response
{
return $this->redirect('https://symfony.com/doc');
}
#[Route('/google', name: 'app_google')]
public function google(): Response
{
return $this->redirect('https://google.com');
}
}
6.3 引用重定向 #
php
<?php
class ReferrerController extends AbstractController
{
#[Route('/back', name: 'app_back')]
public function back(Request $request): Response
{
$referer = $request->headers->get('referer');
if ($referer) {
return $this->redirect($referer);
}
return $this->redirectToRoute('app_home');
}
}
七、异常处理 #
7.1 404异常 #
php
<?php
class ProductController extends AbstractController
{
#[Route('/product/{id}', name: 'app_product_show')]
public function show(int $id, ProductRepository $repository): Response
{
$product = $repository->find($id);
if (!$product) {
throw $this->createNotFoundException('产品不存在');
}
return $this->render('product/show.html.twig', [
'product' => $product,
]);
}
}
7.2 自定义异常 #
php
<?php
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ErrorController extends AbstractController
{
#[Route('/error/not-found', name: 'app_error_not_found')]
public function notFound(): Response
{
throw new NotFoundHttpException('页面不存在');
}
#[Route('/error/access-denied', name: 'app_error_access_denied')]
public function accessDenied(): Response
{
throw new AccessDeniedHttpException('无权访问');
}
#[Route('/error/bad-request', name: 'app_error_bad_request')]
public function badRequest(): Response
{
throw new BadRequestHttpException('错误的请求');
}
}
7.3 异常监听 #
php
<?php
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class ExceptionSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
KernelEvents::EXCEPTION => 'onKernelException',
];
}
public function onKernelException(ExceptionEvent $event): void
{
$exception = $event->getThrowable();
// 自定义异常处理逻辑
}
}
八、控制器最佳实践 #
8.1 瘦控制器 #
php
<?php
// 好的做法:控制器只负责协调
class UserController extends AbstractController
{
public function __construct(
private UserService $userService
) {}
#[Route('/users', name: 'app_user_list')]
public function list(): Response
{
$users = $this->userService->getAllUsers();
return $this->render('user/list.html.twig', [
'users' => $users,
]);
}
#[Route('/user/{id}', name: 'app_user_show')]
public function show(int $id): Response
{
$user = $this->userService->getUserById($id);
if (!$user) {
throw $this->createNotFoundException('用户不存在');
}
return $this->render('user/show.html.twig', [
'user' => $user,
]);
}
}
// 服务类处理业务逻辑
class UserService
{
public function __construct(
private UserRepository $userRepository
) {}
public function getAllUsers(): array
{
return $this->userRepository->findAll();
}
public function getUserById(int $id): ?User
{
return $this->userRepository->find($id);
}
}
8.2 控制器命名规范 #
php
<?php
// 好的命名
class UserController extends AbstractController
{
#[Route('/users', name: 'app_user_list')]
public function list(): Response {}
#[Route('/users/{id}', name: 'app_user_show')]
public function show(int $id): Response {}
#[Route('/users/new', name: 'app_user_new')]
public function new(): Response {}
#[Route('/users/{id}/edit', name: 'app_user_edit')]
public function edit(int $id): Response {}
}
// 不好的命名
class UserCtrl extends AbstractController
{
#[Route('/users', name: 'users')]
public function index(): Response {}
#[Route('/users/{id}', name: 'user')]
public function view(int $id): Response {}
}
九、总结 #
本章学习了:
- 控制器基本概念
- 创建控制器方法
- 动作方法定义
- 返回响应类型
- 模板渲染
- 重定向操作
- 异常处理
- 控制器最佳实践
下一章将学习 请求与响应。
最后更新:2026-03-28