`
weiqingfei
  • 浏览: 315409 次
  • 性别: Icon_minigender_1
  • 来自: 黑洞
社区版块
存档分类
最新评论

laravel的自动注入

    博客分类:
  • PHP
 
阅读更多

laravel里,当我们在controller 的构造方法,或者实例方法中用类型指定一个参数时,系统可以自动帮你把该参数的实例注入进去。

那么内部是如何实现的呢?

先列出几个技术点

1.类ReflectionClass

   该类用于对指定类进行反射,提取类信息。

2.ReflectionClass.getConstructor

   获取指定类的构造方法,返回ReflectionMethod

3.ReflectionMethod.getParameters

   获取方法的参数信息

4.ReflectionClass.newInstanceArgs

  创建类实例

 

当,laravel通过路由寻找到controller的类名时,会先创建实例,如果构造函数里包含指定了类型的参数,并且router设定里并没有传递时,

就会创建这个参数的实例,当然这个参数的构造方法如果还包含指定类型的参数时,还是会创建,一直递归到没有参数指定为止。

入口代码在类Illuminate\Container\Containerd的方法make里

    public function make($abstract, array $parameters = [])
    {
        $abstract = $this->getAlias($this->normalize($abstract));

        // If an instance of the type is currently being managed as a singleton we'll
        // just return an existing instance instead of instantiating new instances
        // so the developer can keep using the same objects instance every time.
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }

        $concrete = $this->getConcrete($abstract);

        // We're ready to instantiate an instance of the concrete type registered for
        // the binding. This will instantiate the types, as well as resolve any of
        // its "nested" dependencies recursively until all have gotten resolved.
        if ($this->isBuildable($concrete, $abstract)) {
            $object = $this->build($concrete, $parameters);
        } else {
            $object = $this->make($concrete, $parameters);
        }

        // If we defined any extenders for this type, we'll need to spin through them
        // and apply them to the object being built. This allows for the extension
        // of services, such as changing configuration or decorating the object.
        foreach ($this->getExtenders($abstract) as $extender) {
            $object = $extender($object, $this);
        }

        // If the requested type is registered as a singleton we'll want to cache off
        // the instances in "memory" so we can return it later without creating an
        // entirely new instance of an object on each subsequent request for it.
        if ($this->isShared($abstract)) {
            $this->instances[$abstract] = $object;
        }

        $this->fireResolvingCallbacks($abstract, $object);

        $this->resolved[$abstract] = true;

        return $object;
    }

 

这个地方的核心代码是在类Illuminate\Container\Containerd的方法build里

public function build($concrete, array $parameters = [])
    {
        // If the concrete type is actually a Closure, we will just execute it and
        // hand back the results of the functions, which allows functions to be
        // used as resolvers for more fine-tuned resolution of these objects.
        if ($concrete instanceof Closure) {
            return $concrete($this, $parameters);
        }

        $reflector = new ReflectionClass($concrete);

        // If the type is not instantiable, the developer is attempting to resolve
        // an abstract type such as an Interface of Abstract Class and there is
        // no binding registered for the abstractions so we need to bail out.
        if (! $reflector->isInstantiable()) {
            if (! empty($this->buildStack)) {
                $previous = implode(', ', $this->buildStack);

                $message = "Target [$concrete] is not instantiable while building [$previous].";
            } else {
                $message = "Target [$concrete] is not instantiable.";
            }

            throw new BindingResolutionException($message);
        }

        $this->buildStack[] = $concrete;

        $constructor = $reflector->getConstructor();

        // If there are no constructors, that means there are no dependencies then
        // we can just resolve the instances of the objects right away, without
        // resolving any other types or dependencies out of these containers.
        if (is_null($constructor)) {
            array_pop($this->buildStack);

            return new $concrete;
        }

        $dependencies = $constructor->getParameters();

        // Once we have all the constructor's parameters we can create each of the
        // dependency instances and then use the reflection instances to make a
        // new instance of this class, injecting the created dependencies in.
        $parameters = $this->keyParametersByArgument(
            $dependencies, $parameters
        );

        $instances = $this->getDependencies(
            $dependencies, $parameters
        );

        array_pop($this->buildStack);

        return $reflector->newInstanceArgs($instances);
    }

 

 

 

分享到:
评论

相关推荐

    Laravel实现构造函数自动依赖注入的方法

    在Laravel框架中,构造函数自动依赖注入是框架内部IoC容器的一个核心功能,它允许开发者在控制器、服务、模型等类的构造函数中声明依赖,而无需手动创建这些依赖的实例。 在Laravel中,自动依赖注入的关键在于类型...

    php+laravel依赖注入知识点总结

    在Laravel中,最常见的是构造函数注入,即在类的构造函数中声明依赖的类,然后服务容器会在创建类实例时自动注入这些依赖项。通过定义接口和实现类,Laravel的容器可以更灵活地控制依赖的解析过程。 3. 自动解析...

    laravel框架中你所用到的依赖注入详解

    Java的依赖注入已经是一个很常见的概念了,Spring框架主要就是解决了这一点,在PHP的laravel框架中,也出现了依赖注入的方式。 依赖注入就控制反转的一种是实现方式,面向对象的特征的重要体现,那么依赖注入中什么...

    Laravel开发-laravel-loader

    在Laravel框架中,`laravel-loader`是一个关键组件,它涉及到框架的自动加载机制,这对于高效、整洁的代码组织至关重要。Laravel的自动加载功能是通过Composer来实现的,它使得我们可以方便地引入和使用类库,而无需...

    Laravel开发-intercom-laravel

    1. **服务绑定**:Laravel 会自动将 Intercom 客户端注入到依赖于 `\PatricPoba\IntercomLaravel\Intercom` 类的任何类中。 2. **调用 API 方法**:例如,你可以使用 `user()` 方法创建或更新用户,`trackEvent()` ...

    Laravel 5.2 中文文档(Laravel学院提供)

    - **深入理解**:如果 URI 参数片段与控制器方法中的变量名匹配,并且变量被类型提示为 Eloquent 模型类,Laravel 将自动注入对应的模型实例。更多信息请参考 Laravel 5.2 文档中关于 HTTP 路由模型绑定的部分。 ##...

    Laravel开发-laravel-scripts

    5. **依赖注入**:Laravel支持依赖注入,通过容器管理服务的创建和解析,使得代码更松耦合,易于测试和扩展。 6. **路由**:Laravel的路由系统允许开发者灵活地定义HTTP请求与控制器方法之间的映射。 7. **中间件*...

    Laravel开发-laravel-sdk

    Service Providers是Laravel依赖注入容器的核心部分,允许开发者在应用程序启动时进行配置,并提供服务给整个应用。 例如,"Multipass-SDK-Laravel-master"这个压缩包可能包含一个Laravel SDK,用于处理Multipass...

    Laravel开发-xero-laravel

    4. **使用服务**: 在Laravel应用中,注入`XeroOAuth2\Client\Manager`实例,调用其提供的方法来执行API请求,如创建或更新数据。 5. **错误处理**: 服务提供商通常会封装API的错误响应,确保在应用中优雅地处理异常...

    laravel商场项目源码

    - **CSRF保护**:laravel自动为表单生成并验证CSRF令牌,防止跨站请求伪造。 - **SQL注入防护**:Eloquent ORM的查询构造器能有效防止SQL注入。 - **缓存**:laravel支持多种缓存驱动,如Redis、Memcached,可以...

    Laravel开发-laravel-counter

    1. **计数器服务提供者(ServiceProvider)**:这是Laravel中注册服务包的主要方式,使得`laravel-counter`可以注入到Laravel的依赖注入容器中,方便全局访问和使用。 2. **计数器迁移(Migrations)**:为了存储和...

    Laravel开发-provider-laravel

    3. **依赖注入**:在类的构造函数中声明依赖,让服务容器自动注入,这有助于保持代码的松耦合和易于测试。 通过理解和熟练掌握服务提供者和门面,开发者能够更高效地构建Laravel应用程序,充分利用框架提供的强大...

    Laravel开发-laravel-versioner

    3. **服务提供者**:作为Laravel的服务提供者,`laravel-versioner` 可以无缝集成到Laravel的依赖注入系统中,方便在任何地方使用版本信息。 4. **Artisan命令**:它提供了Artisan命令行工具,允许开发者在终端中...

    Laravel开发-laravel-annotations

    8. **依赖注入**:虽然Laravel的依赖注入主要基于配置,但注释可用于提供更明确的类型提示,特别是在处理第三方库时。 9. **日志和追踪**:通过注释记录代码执行过程中的重要步骤,有助于调试和性能分析。 10. **...

    Laravel开发-laravel-registry

    通过服务容器,Laravel可以自动处理对象的创建和依赖关系,使得代码更易于测试和解耦。服务容器提供了一个“绑定”(binding)机制,允许我们将类的实例或工厂方法与特定的标识(接口或类名)关联起来。 **二、...

    Laravel开发-laravel-share

    1. **视图数据共享**:`laravel-share`允许开发者定义一组全局的数据,这些数据会在每次渲染视图时自动注入。这样,你不必在每个控制器方法中都添加`view()->share()`来共享数据,只需要在应用启动时配置一次即可。 ...

    Laravel开发-laravel-option

    然后,根据提供的文档或服务提供者的自动发现机制,将其集成到Laravel应用中。 总结来说,"laravel-option"扩展为Laravel添加了更强大的选项管理和配置能力,它可能包括自定义的选项存储策略、API接口以及对服务...

    Laravel开发-laravel-httplug

    Laravel的依赖注入系统会自动处理这一切,让你在需要使用HTTP客户端时,只需通过依赖注入就能得到一个实例。 `laravel-httplug`的主要优点在于其灵活性。你可以根据需求选择不同的HTTP客户端,比如Guzzle、Curl或者...

Global site tag (gtag.js) - Google Analytics