快速入门Laravel核心概念
想要熟练的使用laravel就必须要理解它的核心概念。
Ioc容器
IoC的全称是Inversion of Control(控制反转),它是一种设计模式。它旨在解耦和管理软件组件之间的依赖关系,从而提高代码的可维护性和可测试性。
DI的全称是Dependency Injection(依赖注入),是实现IoC的一种方式。
// 日志类
class FileLogger {
public function log($message) {
echo "Logging message to file: $message\\n";
}
}
// 用户类(业务逻辑)
class User {
protected $logger;
public function __construct() {
$this->logger = new FileLogger();
}
// 一个简单的方法,记录用户行为
public function createUser($username) {
echo "User created: $username\\n";
$this->logger->log("User created: $username");
}
}
// 应用程序入口
$user = new User();
// 创建一个用户,会自动记录日志
$user->createUser("John Doe");
上面定义了一个名为FileLogger的日志类,和一个具有创建用户功能的User类,User类在创建用户的时候需要记录日志。记录日志的功能由专门的日志类FileLogger来实现。
User需要记录日志的功能,因此在User构造函数中创建了FileLogger。这样做的问题在一User和FileLogger绑定在一起,如果FileLogger的不能满足User调用方的需求,那么调用方得重新创建一个User的子类,然后在子类的构造函数中创建自己的日志对象。
class MemoryLogger {
public function log($message) {
echo "Logging message to file: $message\\n";
}
}
class MyUser extends User{
public function __construct() {
$this->logger = new MemoryLogger();
}
}
这种方式让组件之间的依赖度太高。不利于代码维护和测试。
才有IoC的方式实现上面的功能。
// 依赖注入的接口
interface Logger {
public function log($message);
}
// 实现了依赖注入接口的文件日志类
class FileLogger implements Logger {
public function log($message) {
echo "Logging message to file: $message\\n";
}
}
class MemoryLogger implements Logger{
public function log($message) {
echo "Logging message to file: $message\\n";
}
}
// 用户类,它依赖于 Logger 接口
class User {
protected $logger;
// 通过构造函数注入依赖
// 依赖的是接口,不是具体的实现,因此可以按需替换,无法改变User内部的代码
public function __construct(Logger $logger) {
$this->logger = $logger;
}
// 一个简单的方法,记录用户行为
public function createUser($username) {
echo "User created: $username\\n";
$this->logger->log("User created: $username");
}
}
// 应用程序入口
// 在这里我们控制了依赖注入,根据需要注入不同的 Logger 实现
$logger = new FileLogger();
$user = new User($logger);
// 创建一个用户,会自动记录日志
$user->createUser("John Doe");
// 如果需要使用MemoryLogger,构建相应的对象传入,不用修改User内部的实现
$logger = new MemoryLogger();
$user = new User($logger);
$user->createUser("John Doe");
与未使用IoC的方式相比有几个变化:
- User不在内部去创建日志对象,而是通过定义函数参数的方式传入。
- User不依赖某个具体的日志类型,而且依赖Logger接口。这种面相接口编程方式不仅可以提高代码的可维护性,还可以更方便的写测试。
这样在User和Logger组件之间就实现了解耦。
Service Provider服务提供者
Laravel的功能都是通过service provider的形式提供。 service Provider本身不提供具体服务的业务实现,而是把服务注册到IoC容器。例如LoggerServiceProvider把日志服务注册到IoC容器中,让容器有日志功能。
所有的service provider都是继承ServiceProvider。ServiceProvider通过2个方式定义了service provider的生命周期:
- register方法,注册服务,告诉IoC容器如何创建服务。
- boot方法,初始化服务,IoC创建服务之后执行一些初始化的操作
下面的例子提供了一个生成随机数的服务
<?php
namespace App\\Providers;
use Illuminate\\Support\\ServiceProvider;
// 生成随机数
class RandomStringGenerator{
}
class RandomStringServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
// 将 RandomStringGenerator 绑定到容器
$this->app->bind('randomString', function ($app) {
return new RandomStringGenerator();
});
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
// 执行初始化操作,这个时候可以访问到IoC容器注册的其它服务了
}
}
上面的例子中可以发现,RandomStringServiceProvider本身并不提供生成随机数的功能,它只是把
RandomStringGenerator注册到了IoC容器里面,具体的生成随机数的功能是由RandomStringGenerator实现。
Middleware 中间件
中间件提供了一种在http请求被处理之前和之后能执行一段额外的逻辑。在很多web框架中都有这个概念。
下面这张流程图很好的解释了中间件的用途
Facade门脸模式
Facede需要和service provider结合使用。它主要的作用是简化service provider提供服务的API使用。
例如Laravel通过CacheServiceProvider提供了缓存的功能,具体的实现是由CacheManager这个类来实现的。定义如下:
public function register()
{
$this->app->singleton('cache', function ($app) {
return new CacheManager($app);
});
// ... 其它代码省略
}
在不用Facade的前提下需要这样使用CacheManager上的方法app(’cache’)→xxxx()。
如果利用Facade模式则可以这样使用Cache::xxxxx()。它的底层实现原理是利用了class_alias和__callStatic模式方法。
Laravel的Facede模式不仅可以简化API使用,它还提供了mock服务的功能,可以方便写测试。
本作品采用《CC 协议》,转载必须注明作者和本文链接
好好学习天天向上~