我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Laravel容器、控制反转和依赖注入实例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Laravel容器、控制反转和依赖注入实例分析

这篇文章主要介绍“Laravel容器、控制反转和依赖注入实例分析”,在日常操作中,相信很多人在Laravel容器、控制反转和依赖注入实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Laravel容器、控制反转和依赖注入实例分析”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

随着现在应用的规模越来越庞大,对象之间的依赖关系也越来越复杂,耦合程度越来越高,经常会出现对象之间多重依赖的情况。对于如此庞大复杂的应用,任何修改都可能会牵一发而动全身,这就为应用的后期维护造成了很多困扰。

  为了解决对象之间耦合度高的问题,控制反转(IoC)的思想也随之诞生。所谓控制反转,是面向对象编程中的一种设计原则,其目的是为了降低代码之间的耦合程度。在 Laravel 中,控制反转是通过依赖注入(DI)的方式实现的。

  控制反转的基本思想是借助 IoC 容器实现对象之间的依赖关系的解耦。引入 IoC 容器之后,所有对象的控制权都上交给 IoC 容器,IoC 容器成了整个系统的核心,把所有对象粘合在一起发挥作用。Laravel 中的容器即起到了这个作用。

⒈ 容器

  所谓容器,在 Laravel 中指的是 \Illuminate\Foundation\Application 对象,Laravel 框架在启动时即创建了该对象。

# public/index.php$app = require_once __DIR__.'/../bootstrap/app.php';# bootstrap/app.php$app = new Illuminate\Foundation\Application(    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__));

  在创建容器的过程中,Laravel 还会对容器进行一些基础的绑定和服务注册。Laravel 首先会将容器实例与 app 和 Illuminate\Container\Container 进行绑定;之后,Laravel 会将基础的服务提供者注册到容器实例中,包括事件、日志、路由服务提供者;最后,Laravel 会将框架核心 class 与其相对应的别名一起注册到容器实例当中。

// namespace Illuminate\Foundation\Applicationpublic function __construct($basePath = null){    if ($basePath) {        $this->setBasePath($basePath);    }    $this->registerBaseBindings();    $this->registerBaseServiceProviders();    $this->registerCoreContainerAliases();}    protected function registerBaseBindings(){    static::setInstance($this);    $this->instance('app', $this);    $this->instance(Container::class, $this);    }protected function registerBaseServiceProviders(){    $this->register(new EventServiceProvider($this));    $this->register(new LogServiceProvider($this));    $this->register(new RoutingServiceProvider($this));}public function registerCoreContainerAliases(){    foreach ([        'app' => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],                'db' => [\Illuminate\Database\DatabaseManager::class, \Illuminate\Database\ConnectionResolverInterface::class],        'db.connection' => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],                'request' => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],        'router' => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],            ] as $key => $aliases) {        foreach ($aliases as $alias) {            $this->alias($key, $alias);        }    }}// namespace Illuminate\Container\Containerpublic function alias($abstract, $alias){    if ($alias === $abstract) {        throw new LogicException("[{$abstract}] is aliased to itself.");    }    $this->aliases[$alias] = $abstract;    $this->abstractAliases[$abstract][] = $alias;}

  在完成这三步基本的注册之后,我们可以很方便的访问已经注册到容器中的对象实例。例如,可以直接通过 $app['app'] 或 $app['Illuminate\Container\Container'] 访问容器本身,还可以通过  $app['db'] 直接访问数据库连接。

⒉ 服务提供者的注册以及服务的访问

注册服务提供者

  在容器创建的过程中会注册基础服务提供者,其注册过程通过调用 register() 方法完成。

// namespace Illuminate\Foundation\Applicationpublic function register($provider, $force = false){    if (($registered = $this->getProvider($provider)) && ! $force) {        return $registered;    }    if (is_string($provider)) {        $provider = $this->resolveProvider($provider);    }    $provider->register();    if (property_exists($provider, 'bindings')) {        foreach ($provider->bindings as $key => $value) {            $this->bind($key, $value);        }    }    if (property_exists($provider, 'singletons')) {        foreach ($provider->singletons as $key => $value) {            $this->singleton($key, $value);        }    }    $this->markAsRegistered($provider);    if ($this->isBooted()) {        $this->bootProvider($provider);    }    return $provider;}

  Laravel 首先会判断指定的服务提供者是否已经在容器中注册(通过调用 getProvider() 方法实现),如果指定的服务提供者已经在容器中注册,并且本次注册操作并非强制执行,那么直接返回已经注册好的服务提供者。

  如果不满足上述条件,那么 Laravel 就会开始注册服务提供者。此时,如果传参为字符串,那么 Laravel 会默认参数为服务提供者的 class 名称并进行实例化(通过 resolveProvider() 方法实现)。之后,就会调用服务提供者定义的 register() 方法进行注册。以日志服务提供者为例,其 register() 方法的方法体如下

// namespace Illuminate\Log\LogServiceProviderpublic function register(){    $this->app->singleton('log', function ($app) {        return new LogManager($app);    });}

  register() 方法的作用就是将 Illuminate\Log\LogManager 对象以单例的模式注册到容器当中,注册完成之后,容器的 $bindings 属性中会增加一项

$app->bindings['log'] = [    'concrete' => 'Illuminate\Log\LogManager {#162}',    'shared' => true,];

  如果服务提供者自身还定义了 $bindings 属性以及 $singletons 属性,那么 Laravel 还会调用相应的 bind() 方法和 singleton() 方法完成这些服务提供者自定义的绑定的注册。

  这之后 Laravel 会将服务提供者标记为已经注册的状态,随后会调用服务提供者定义的 boot() 方法启动服务提供者(前提是应用已经启动)。

  在向容器中注册绑定时,有 bind() 和 singleton() 两种方法,其区别仅在于注册的绑定是否为单例模式,即 shared 属性是否为 true 。

// namespace Illuminate\Container\Containerpublic function singleton($abstract, $concrete = null){    $this->bind($abstract, $concrete, true);}public function bind($abstract, $concrete = null, $shared = false){    // 删除旧的绑定    $this->dropStaleInstances($abstract);    if (is_null($concrete)) {        $concrete = $abstract;    }    if (! $concrete instanceof Closure) {        if (! is_string($concrete)) {            throw new TypeError(self::class.'::bind(): Argument #2 ($concrete) must be of type Closure|string|null');        }        $concrete = $this->getClosure($abstract, $concrete);    }    $this->bindings[$abstract] = compact('concrete', 'shared');    if ($this->resolved($abstract)) {        $this->rebound($abstract);    }}protected function getClosure($abstract, $concrete){    return function ($container, $parameters = []) use ($abstract, $concrete) {        if ($abstract == $concrete) {            return $container->build($concrete);        }        return $container->resolve(            $concrete, $parameters, $raiseEvents = false        );    };}

  仍然以日志服务提供者为例,日志服务提供者在注册时以单例模式进行注册,并且 $concrete 参数为闭包。在绑定开始之前,Laravel 首先会删除旧的绑定。由于此时 $concrete 为闭包,所以 Laravel 并不会进行什么操作,只是将绑定信息存入 $bindings 属性当中。

访问服务

  在服务提供者注册完成之后,我们可以用上文提到的类似访问数据库连接的方式那样访问服务。仍然以日志服务为例,我们可以通过 $app['log'] 的方式访问日志服务。另外,在 Laravel 中,我们还可以使用 facade 的方式访问服务,例如,我们可以调用 Illuminate\Support\Facades\Log::info() 来记录日志。

// namespace Illuminate\Support\Facades\Logclass Log extends Facade{    protected static function getFacadeAccessor()    {        return 'log';    }}// namespace Illuminate\Support\Facades\Facadepublic static function __callStatic($method, $args){    $instance = static::getFacadeRoot();        return $instance->$method(...$args);}public static function getFacadeRoot(){    return static::resolveFacadeInstance(static::getFacadeAccessor());}protected static function resolveFacadeInstance($name){    if (is_object($name)) {        return $name;    }    if (isset(static::$resolvedInstance[$name])) {        return static::$resolvedInstance[$name];    }    if (static::$app) {        return static::$resolvedInstance[$name] = static::$app[$name];    }}

  在通过静态调用的方式进行日志记录时,首先会访问 Facade 中的魔术方法 __callStatic() ,该方法的首先进行的就是解析出 facade 对应的服务实例,然后调用该服务实例下的方法来执行相应的功能。每个 facade 中都会定义一个 getFacadeAccessor() 方法,这个方法会返回一个 tag,在日志服务中,这个 tag 就是日志服务提供者的闭包在容器的 $bindings 属性中的 key。也就是说,通过 facade 方式最终得到的是 $app['log']。

  那么为什么可以通过关联数组的方式访问容器中注册的对象/服务?Illuminate\Container\Container 实现了 ArrayAccess 并且定义了 OffsetGet() 方法,而 Illuminate\Foundation\Application 继承了 Container ,$app 为 Application 实例化的对象,所以通过关联数组的方式访问容器中注册的对象时会访问 Container 的 OffsetGet() 方法。在 OffsetGet() 方法中会调用 Container 的 make() 方法,而 make() 方法中又会调用 resolve() 方法。resolve() 方法最终会解析并返回相应的对象。

// namespace Illuminate\Containerpublic function offsetGet($key){    return $this->make($key);}public function make($abstract, array $parameters = []){    return $this->resolve($abstract, $parameters);}protected function resolve($abstract, $parameters = [], $raiseEvents = true){        $this->with[] = $parameters;    if (is_null($concrete)) {        $concrete = $this->getConcrete($abstract);    }    if ($this->isBuildable($concrete, $abstract)) {        $object = $this->build($concrete);    } else {        $object = $this->make($concrete);    }        $this->resolved[$abstract] = true;    array_pop($this->with);    return $object;}protected function getConcrete($abstract){    if (isset($this->bindings[$abstract])) {        return $this->bindings[$abstract]['concrete'];    }    return $abstract;}protected function isBuildable($concrete, $abstract){    return $concrete === $abstract || $concrete instanceof Closure;}public function build($concrete){    if ($concrete instanceof Closure) {        return $concrete($this, $this->getLastParameterOverride());    }    }protected function getLastParameterOverride(){    return count($this->with) ? end($this->with) : [];}

  这里需要说明,在通过 $app['log'] 的方式解析日志服务实例时,resolve() 方法中的 $concrete 解析得到的是一个闭包,导致 isBuildable() 方法返回结果为 true,所以 Laravel 会直接调用 build() 方法。而由于此时 $concrete 是一个闭包,所以在 build() 方法中会直接执行这个闭包函数,最终返回 LogManager 实例。

⒊ 请求处理

  在基础的绑定和服务注册完成之后,容器创建成功并返回 $app 。之后 Laravel 会将内核(包括 Http 内核和 Console 内核)和异常处理注册到容器当中。然后 Laravel 开始处理请求。

// namespace bootstrap/app.php$app->singleton(    Illuminate\Contracts\Http\Kernel::class,    App\Http\Kernel::class);$app->singleton(    Illuminate\Contracts\Console\Kernel::class,    App\Console\Kernel::class);$app->singleton(    Illuminate\Contracts\Debug\ExceptionHandler::class,    App\Exceptions\Handler::class);// public/index.php$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);$response = $kernel->handle(    $request = Request::capture())->send();$kernel->terminate($request, $response);

  在开始处理请求之前,Laravel 首先会解析出 Http 内核对象 $kernel,即 App\Http\Kernel 实例化的对象。而 App\Http\Kernel 继承了 Illuminate\Foundation\Kernel,所以 $kernel 实际调用的是 Illuminate\Foundation\Kernel 中的 handle() 方法。

namespace Illuminate\Foundation\Httpuse Illuminate\Contracts\Debug\ExceptionHandlerpublic function handle($request){    try {        $request->enableHttpMethodParameterOverride();        $response = $this->sendRequestThroughRouter($request);    } catch (Throwable $e) {        $this->reportException($e);        $response = $this->renderException($request, $e);    }    $this->app['events']->dispatch(        new RequestHandled($request, $response)    );    return $response;}// 上报错误protected function reportException(Throwable $e){    $this->app[ExceptionHandler::class]->report($e);}// 渲染错误信息    protected function renderException($request, Throwable $e){    return $this->app[ExceptionHandler::class]->render($request, $e);}

  handle() 方法在处理请求的过程中如果出现任何异常或错误,Laravel 都会调用容器中已经注册好的异常处理对象来上报异常并且渲染返回信息。

  在容器创建成功以后,Laravel 会将 Illuminate\Contracts\Debug\ExceptionHandler 和 App\Exceptions\Handler 之间的绑定注册到容器当中,所以 Laravel 处理异常实际调用的都是 App\Exceptions\Handler 中的方法。在实际开发过程中,开发者可以根据自身需要在 App\Exceptions\Handler 中自定义 report() 和 render() 方法。

在 PHP 7 中,`Exception` 和 `Error` 是两种不同的类型,但它们同时都继承了 `Throwable` ,所以 `handler()` 方法中捕获的是 `Throwable` 对象。

  在正式开始处理请求之前,Laravel 会进行一些引导启动,包括加载环境变量、配置信息等,这些引导启动在 Laravel 运行过程中起到了非常重要的作用。

// namespace Illuminate\Foundation\Http\Kernelprotected $bootstrappers = [    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,    \Illuminate\Foundation\Bootstrap\HandleExceptions::class,    \Illuminate\Foundation\Bootstrap\RegisterFacades::class,    \Illuminate\Foundation\Bootstrap\RegisterProviders::class,    \Illuminate\Foundation\Bootstrap\BootProviders::class,];protected function sendRequestThroughRouter($request){        $this->bootstrap();    }public function bootstrap(){    if (! $this->app->hasBeenBootstrapped()) {        $this->app->bootstrapWith($this->bootstrappers());    }}// namespace Illuminate\Foundation\Applicationpublic function bootstrapWith(array $bootstrappers){    $this->hasBeenBootstrapped = true;    foreach ($bootstrappers as $bootstrapper) {        $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);        $this->make($bootstrapper)->bootstrap($this);        $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);    }}

  从代码中可以看出,引导启动的过程实际就是调用各个 class 中的 bootstrap() 方法。其中:

LoadEnvironmentVariables 用来加载环境变量

LoadConfiguration 用来加载 config 目录下的配置文件

HandleExceptions 用来设置 PHP 的错误报告级别以及相应的异常和错误处理函数,另外还会设置 PHP 的程序终止执行函数

// namespace Illuminate\Foundation\Bootstrap\HandleExceptionspublic function bootstrap(Application $app){        $this->app = $app;    error_reporting(-1);    set_error_handler([$this, 'handleError']);    set_exception_handler([$this, 'handleException']);    register_shutdown_function([$this, 'handleShutdown']);    }public function handleError($level, $message, $file = '', $line = 0, $context = []){    if (error_reporting() & $level) {                throw new ErrorException($message, 0, $level, $file, $line);    }}public function handleException(Throwable $e){            $this->getExceptionHandler()->report($e);    }public function handleShutdown(){    if (! is_null($error = error_get_last()) && $this->isFatal($error['type'])) {        $this->handleException($this->fatalErrorFromPhpError($error, 0));    }}protected function getExceptionHandler(){    return $this->app->make(\Illuminate\Contracts\Debug\ExceptionHandler::class);}

  从以上代码中可以看出,虽然 HandleExceptions 中定义了异常、错误、程序终止的处理函数,但无论是哪种情况,最终还是调用 App\Exceptions\Handler 中的方法来处理异常或错误。

RegisterFacades 的作用一个是注册配置文件以及第三方包中自定义的 alias 类,还有一个非常重要的作用就是为 Illuminate\Support\Facades\Facade 类设置 $app 属性。

// namespace Illuminate\Foundation\Bootstrap\RegisterFAcadespublic function bootstrap(Application $app){    Facade::clearResolvedInstances();    Facade::setFacadeApplication($app);    AliasLoader::getInstance(array_merge(        $app->make('config')->get('app.aliases', []),        $app->make(PackageManifest::class)->aliases()    ))->register();}

&emsp 我们在通过 facade 方式反问容器中注册的服务时,Facade 在解析容器中的服务实例时用到的 static::$app 即是在这个时候设置的。

RegisterProviders 的作用是注册配置文件以及第三方包中定义的服务提供者

// namespace Illuminate\Foundation\Bootstrap\RegisterProviderspublic function bootstrap(Application $app){    $app->registerConfiguredProviders();}public function registerConfiguredProviders(){    $providers = Collection::make($this->make('config')->get('app.providers'))                    ->partition(function ($provider) {                        return strpos($provider, 'Illuminate\\') === 0;                    });    $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);    (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))                ->load($providers->collapse()->toArray());}

  在实际注册的过程中,Laravel 会按照 Laravel 框架的服务提供者 > 第三方包的服务提供者 > 开发者自定义的服务提供者 的顺序进行注册

BootProviders 则是按顺序调用已经注册到容器中的服务提供者的 boot() 方法(前提是服务提供者定义的 boot() 方法)

  在引导启动完成之后,Laravel 开始处理请求,首先要做的就是将全局的中间件应用于 request 。这之后 Laravel 会将请求分发到相应的路由进行处理,处理之前需要先根据 request 找到相应的路由对象 Illuminate\Routing\Route。在 Laravel 中,除了全局中间件,还有一些中间件只作用于特定的路由或路由分组,此时这些中间件就会被作用于 request 。这些工作都完成之后,路由对象开始执行代码,完成请求。

// namespace Illuminate\Foundation\Http\Kernelprotected function sendRequestThroughRouter($request){        return (new Pipeline($this->app))                ->send($request)                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)                ->then($this->dispatchToRouter());}protected function dispatchToRouter(){    return function ($request) {        $this->app->instance('request', $request);                return $this->router->dispatch($request);    };}// namespace Illuminate\Routing\Routerpublic function dispatch(Request $request){    $this->currentRequest = $request;    return $this->dispatchToRoute($request);}public function dispatchToRoute(Request $request){    return $this->runRoute($request, $this->findRoute($request));}protected function runRoute(Request $request, Route $route){        return $this->prepareResponse($request,        $this->runRouteWithinStack($route, $request)    );}protected function runRouteWithinStack(Route $route, Request $request){           return (new Pipeline($this->container))                    ->send($request)                    ->through($middleware)                    ->then(function ($request) use ($route) {                        return $this->prepareResponse(                            $request, $route->run()                        );                    });}

⒋ 依赖注入

  Laravel 中的路由在注册时,action 可以是控制器方法,也可以是闭包。但无论是那种形式,都需要传参,而传参就会遇到需要依赖注入的情况。

  Route 对象在执行 run() 方法时会根据 action 的类型分别进行控制器方法调用或闭包函数的调用。但两种方法最终都需要解析参数,而如果参数中用到了 class ,就需要进行依赖注入。

// namespace Illuminate\Routing\Routerpublic function run(){    $this->container = $this->container ?: new Container;    try {        if ($this->isControllerAction()) {            return $this->runController();        }        return $this->runCallable();    } catch (HttpResponseException $e) {        return $e->getResponse();    }}protected function runController(){    return $this->controllerDispatcher()->dispatch(        $this, $this->getController(), $this->getControllerMethod()    );}protected function runCallable(){        return $callable(...array_values($this->resolveMethodDependencies(        $this->parametersWithoutNulls(), new ReflectionFunction($callable)    )));}// namespace Illuminate\Routing\ControllerDispatcherpublic function dispatch(Route $route, $controller, $method){    $parameters = $this->resolveClassMethodDependencies(        $route->parametersWithoutNulls(), $controller, $method    );    }// namespace Illuminate\Routing\RouteDependencyResolverTraitprotected function resolveClassMethodDependencies(array $parameters, $instance, $method){        return $this->resolveMethodDependencies(        $parameters, new ReflectionMethod($instance, $method)    );}public function resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector){        foreach ($reflector->getParameters() as $key => $parameter) {        $instance = $this->transformDependency($parameter, $parameters, $skippableValue);            }    return $parameters;}protected function transformDependency(ReflectionParameter $parameter, $parameters, $skippableValue){    $className = Reflector::getParameterClassName($parameter);    if ($className && ! $this->alreadyInParameters($className, $parameters)) {        return $parameter->isDefaultValueAvailable() ? null : $this->container->make($className);    }    return $skippableValue;}

  在执行过程中,Laravel 首先通过反射取得参数列表(对于控制器方法,使用 ReflectionMethod ,对于闭包函数,则使用 ReflectionFunction )。在得到参数列表后,Laravel 仍然是利用反射,逐个判断参数类型。如果参数类型为 PHP 的内置类型,那么不需要什么特殊处理;但如果参数不是 PHP 内置类型,则需要利用反射解析出参数的具体类型。在解析出参数的具体类型之后,紧接着会判断该类型的对象是不是已经存在于参数列表中,如果不存在并且该类型也没有设置默认值,那么就需要通过容器创建出该类型的实例。

  要通过容器创建指定 class 的实例,仍然需要用到 resolve() 方法。前文已经叙述过使用 resolve() 方法解析闭包函数的情况,所以这里值叙述实例化 class 的情况。

// namespace Illuminate\Container\Containerpublic function build($concrete){        try {        $reflector = new ReflectionClass($concrete);    } catch (ReflectionException $e) {        throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);    }    if (! $reflector->isInstantiable()) {        return $this->notInstantiable($concrete);    }    $this->buildStack[] = $concrete;    $constructor = $reflector->getConstructor();    if (is_null($constructor)) {        array_pop($this->buildStack);        return new $concrete;    }    $dependencies = $constructor->getParameters();    try {        $instances = $this->resolveDependencies($dependencies);    } catch (BindingResolutionException $e) {        array_pop($this->buildStack);        throw $e;    }    array_pop($this->buildStack);    return $reflector->newInstanceArgs($instances);}protected function resolveDependencies(array $dependencies){    $results = [];    foreach ($dependencies as $dependency) {        if ($this->hasParameterOverride($dependency)) {            $results[] = $this->getParameterOverride($dependency);            continue;        }        $result = is_null(Util::getParameterClassName($dependency))                        ? $this->resolvePrimitive($dependency)                        : $this->resolveClass($dependency);        if ($dependency->isVariadic()) {            $results = array_merge($results, $result);        } else {            $results[] = $result;        }    }    return $results;}

  容器在实例化 class 的时候,仍然是通过反射获取 class 基本信息。对于一些无法进行实例化的 class (例如 interface 、abstract class ),Laravel 会抛出异常;否则 Laravel 会继续获取 class 的构造函数的信息。对于不存在构造函数的 class ,意味着这些 class 在实例化的时候不需要额外的依赖,可以直接通过 new 来实例化;否则仍然是通过反射解析出构造函数的参数列表信息,然后逐个实例化这些参数列表中用到的 class 。在这些参数列表中的 class 都实例化完成之后,通过容器创建 class 的准备工作也已经完成,此时容器可以顺利创建出指定 class 的实例,然后注入到控制器方法或闭包中。

到此,关于“Laravel容器、控制反转和依赖注入实例分析”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Laravel容器、控制反转和依赖注入实例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Laravel容器、控制反转和依赖注入实例分析

这篇文章主要介绍“Laravel容器、控制反转和依赖注入实例分析”,在日常操作中,相信很多人在Laravel容器、控制反转和依赖注入实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Laravel容器、控
2023-06-29

Laravel 服务容器实例教程 —— 深入理解控制反转和依赖注入

容器,字面上理解就是装东西的东西。常见的变量、对象属性等都可以算是容器。一个容器能够装什么,全部取决于你对该容器的定义。
2022-06-01

laravel的依赖注入和控制反转怎么实现

这篇文章主要介绍“laravel的依赖注入和控制反转怎么实现”,在日常操作中,相信很多人在laravel的依赖注入和控制反转怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”laravel的依赖注入和控制
2023-06-30

Sprin如何控制反转和依赖注入

本篇内容主要讲解“Sprin如何控制反转和依赖注入”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Sprin如何控制反转和依赖注入”吧!控制反转的类型控制反转(IOC)旨在提供一种更简单的机制,来
2023-06-29

理解Spring中的依赖注入和控制反转

学习过Spring框架的人一定都会听过Spring的IoC(控制反转) 、DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC 、DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring框
2023-05-30

C++设计模式中控制反转与依赖注入浅析

这篇文章主要介绍了C++设计模式中控制反转与依赖注入,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2023-01-13

.net程序开发IOC控制反转和DI依赖注入详解

这篇文章主要为大家介绍了.net程序开发IOC控制反转和DI依赖注入示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录