服务容器与服务提供者
Laravel 的核心是 IoC 容器(服务容器)。你在控制器里写 public function __construct(UserRepository $repo) 时,不需要手动 new UserRepository()——容器会自动解析并注入依赖。理解服务容器,是从"能用 Laravel"到"理解 Laravel"的关键一步。
服务容器:自动依赖注入
// 没有容器时(传统做法):
class TaskController {
public function __construct() {
$this->service = new TaskService(
new TaskRepository(
new DatabaseConnection(config('database'))
)
);
}
}
// 有容器时(Laravel 方式):
class TaskController {
public function __construct(
private TaskService $service // 容器自动解析整个依赖链
) {}
}
// 只要 TaskService 的构造函数参数也都能被解析,Laravel 就会自动 new 好所有层级
容器如何工作
// Laravel 容器的三种解析方式:
// 1. 自动解析(Zero Configuration)
// 如果类只依赖其他类(无接口/无配置),容器自动 new
app(TaskService::class); // 等同于 new TaskService(new TaskRepository(...))
// 2. 绑定接口到实现
// 告诉容器:当需要 TaskRepositoryInterface 时,给我 PostgresTaskRepository
app()->bind(
TaskRepositoryInterface::class,
PostgresTaskRepository::class
);
// 3. 单例绑定(整个请求周期内只实例化一次)
app()->singleton(
PaymentGateway::class,
fn() => new StripeGateway(config('services.stripe.secret'))
);
AppServiceProvider:应用级服务绑定
Laravel 11 默认只有 AppServiceProvider,这是你注册应用级绑定的地方:
<?php
// app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Repositories\TaskRepositoryInterface;
use App\Repositories\EloquentTaskRepository;
class AppServiceProvider extends ServiceProvider
{
// register():注册绑定(只做绑定,不运行业务逻辑)
public function register(): void
{
// 绑定接口到实现
$this->app->bind(
TaskRepositoryInterface::class,
EloquentTaskRepository::class
);
// 单例:整个请求生命周期复用同一实例
$this->app->singleton(
'payment.gateway',
fn($app) => new \App\Services\StripeService(
config('services.stripe.key'),
config('services.stripe.secret')
)
);
}
// boot():应用启动后执行(可以用其他已注册的服务)
public function boot(): void
{
// 全局模型事件
\App\Models\Task::observe(\App\Observers\TaskObserver::class);
// 自定义 Blade 指令
\Blade::directive('money', fn($amount) => "<?php echo '$' . number_format($amount / 100, 2); ?>");
// URL 强制 HTTPS(生产环境)
if ($this->app->isProduction()) {
\URL::forceScheme('https');
}
}
}
请求生命周期
理解 Laravel 处理一个 HTTP 请求的完整流程:
graph TD
A["HTTP 请求"] --> B["public/index.php\n入口文件"]
B --> C["bootstrap/app.php\n创建 Application 实例"]
C --> D["注册核心服务提供者\n(框架内部)"]
D --> E["启动服务提供者\nAppServiceProvider::boot()"]
E --> F["HTTP Kernel\n加载中间件"]
F --> G["路由匹配\nroutes/web.php or api.php"]
G --> H["执行路由中间件"]
H --> I["控制器方法\n(依赖自动注入)"]
I --> J["业务逻辑\nService / Repository"]
J --> K["返回 Response"]
K --> L["执行 Terminate 中间件"]
L --> M["发送响应给客户端"]
实战:Repository 模式
Repository 模式是 Laravel 项目中最常见的架构模式,把数据访问逻辑从控制器和服务层中分离出来:
// 1. 定义接口
// app/Repositories/TaskRepositoryInterface.php
namespace App\Repositories;
interface TaskRepositoryInterface
{
public function findByUser(int $userId, array $filters = []): \Illuminate\Pagination\LengthAwarePaginator;
public function create(array $data): \App\Models\Task;
public function update(int $id, array $data): \App\Models\Task;
public function delete(int $id): void;
}
// 2. Eloquent 实现
// app/Repositories/EloquentTaskRepository.php
namespace App\Repositories;
use App\Models\Task;
class EloquentTaskRepository implements TaskRepositoryInterface
{
public function findByUser(int $userId, array $filters = [])
{
return Task::where('user_id', $userId)
->when($filters['status'] ?? null, fn($q, $status) => $q->where('status', $status))
->when($filters['search'] ?? null, fn($q, $s) => $q->where('title', 'like', "%{$s}%"))
->latest()
->paginate(20);
}
public function create(array $data): Task
{
return Task::create($data);
}
public function update(int $id, array $data): Task
{
$task = Task::findOrFail($id);
$task->update($data);
return $task->fresh();
}
public function delete(int $id): void
{
Task::findOrFail($id)->delete();
}
}
// 3. 在 AppServiceProvider 注册绑定
// app/Providers/AppServiceProvider.php
$this->app->bind(TaskRepositoryInterface::class, EloquentTaskRepository::class);
// 4. 控制器通过接口注入(不依赖具体实现)
// app/Http/Controllers/TaskController.php
class TaskController extends Controller
{
public function __construct(
private TaskRepositoryInterface $tasks // 容器自动注入 EloquentTaskRepository
) {}
public function index(Request $request)
{
$tasks = $this->tasks->findByUser(
auth()->id(),
$request->only(['status', 'search'])
);
return TaskResource::collection($tasks);
}
}
Facades:静态语法的背后
Laravel 的 Cache::get()、DB::table() 语法看起来是静态方法,实际上是通过 Facade 代理到容器中的实例:
// 这两种写法完全等效:
// Facade 语法(简洁)
use Illuminate\Support\Facades\Cache;
Cache::put('key', 'value', 3600);
// 容器注入语法(明确)
use Illuminate\Cache\CacheManager;
public function __construct(private CacheManager $cache) {}
$this->cache->put('key', 'value', 3600);
// 辅助函数语法
cache()->put('key', 'value', 3600);
// 在哪里用哪种?
// - 控制器/服务:依赖注入(便于测试 Mock)
// - 配置文件/路由文件:Facade 或辅助函数
下一节:环境配置与 .env 管理——
.env文件是 Laravel 配置的核心,理解它的优先级、缓存机制、以及如何为不同环境管理配置,能避免很多生产故障。