Laravel Application Object

本文详细介绍了 Laravel 框架中 IoC (依赖反转) 和 DI (依赖注入) 的概念及其工作原理,深入剖析了 Laravel 中 IoC 容器的实现方式,并通过实例展示了依赖注入的具体操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Laravel版本5.4.33

本文编写时,5.4.33是最新版, 下载地址。如果5.4.33不是最新版,请前往 下载5.4.33

1. IoC(Inversion of Control) 和 DI (Dependency injection)
IoC -  Inversion of Control,依赖反转,简言之就是:将依赖的生产由内部移至外部,从而降低耦合程度
DI - Dependency injection,依赖注入,简言之就是:根据反射机制,自动识别目标类的所需依赖,并将依赖自动提供给目标类的过程。
2. Laravel 中的 IoC 容器
Laravel实现了一个管理各种依赖的容器,并通过这个容器实现了依赖注入。下面是laravel中对IoC容器的接口定义:
<?php
interface Container
{
    /**
     * Determine if the given abstract type has been bound.
     */
    public function bound($abstract);

    /**
     * Alias a type to a different name.
     */
    public function alias($abstract, $alias);

    /**
     * Assign a set of tags to a given binding.
     */
    public function tag($abstracts, $tags);

    /**
     * Resolve all of the bindings for a given tag.
     */
    public function tagged($tag);

    /**
     * Register a binding with the container.
     */
    public function bind($abstract, $concrete = null, $shared = false);

    /**
     * Register a binding if it hasn't already been registered.
     */
    public function bindIf($abstract, $concrete = null, $shared = false);

    /**
     * Register a shared binding in the container.
     */
    public function singleton($abstract, $concrete = null);

    /**
     * "Extend" an abstract type in the container.
     */
    public function extend($abstract, Closure $closure);

    /**
     * Register an existing instance as shared in the container.
     */
    public function instance($abstract, $instance);

    /**
     * Define a contextual binding.
     */
    public function when($concrete);

    /**
     * Get a closure to resolve the given type from the container.
     */
    public function factory($abstract);

    /**
     * Resolve the given type from the container.
     */
    public function make($abstract);

    /**
     * Call the given Closure / class@method and inject its dependencies.
     */
    public function call($callback, array $parameters = [], $defaultMethod = null);

    /**
     * Determine if the given abstract type has been resolved.
     */
    public function resolved($abstract);

    /**
     * Register a new resolving callback.
     */
    public function resolving($abstract, Closure $callback = null);

    /**
     * Register a new after resolving callback.
     */
    public function afterResolving($abstract, Closure $callback = null);
}
下面是我对IoC容器的一个简单实现(未完整):
<?php
require_once('./ContainerInterface.php');
require_once('./DB.php');

error_reporting(1);
class Container implements ContainerInterface{
	// 抽象服务和具体实现的映射,以及是否为单例
	// $bindings = [
	// 	'abstract' => ['concrete' => Object/Closure, 'shared' => true/false],
	// 	...
	// ];
	protected $bindings = [];

	// 服务实例
	// $instance = [
	// 	'abstract' => object,
	// 	...
	// ];
	protected $instance = [];

	// 别名和抽象服务映射
	// $aliases = [
	// 	'alias' => 'abstract',
	// 	...
	// ];
	protected $aliases  = [];

	// 抽象服务和别名映射
	// $abstractAliases = [
	// 	'abstract' => ['alias1', 'alias2'],
	// 	...
	// ];
	protected $abstractAliases = [];

	// 
	public function bound($abstract){
		return isset($this->bindings[$abstract]) || isset($this->aliases[$abstract]);
	}

    public function alias($abstract, $alias){
    	$this->aliases[$alias] = $abstract;
    	$this->abstractAliases[$abstract] = $alias;
    }

    public function tag($abstracts, $tags){}

    public function tagged($tag){}

    public function bind($abstract, $concrete = null, $shared = false){
    	unset($this->aliases[$abstract]);
    	unset($this->instance[$abstract ]);
		$this->bindings[$abstract] = ['concrete' => $concrete, 'shared' => $shared];
    }

    public function bindIf($abstract, $concrete = null, $shared = false){
    	if(!$this->bound($abstract)){
    		$this->bind($abstract, $concrete, $shared);
    	}
    }

    public function singleton($abstract, $concrete = null){
    	$this->bind($abstract, $concrete, true);
    }

    public function extend($abstract, Closure $closure){
        if(isset($this->instance[$abstract])){
            $instance = $this->instance[$abstract];
        }else{
            if($this->bound($abstract)){
                $instance = $this->make($abstract);
            }
        }
        $closure($instance, $this);
    }

    public function instance($abstract, $instance){
        if(isset($this->bindings[$abstract])){
            unset($this->bindings[$abstract]);
        }
        if(isset($this->instance[$abstract])){
            unset($this->instance[$abstract]);
        }
        $this->singleton($abstract, $instance);
    }

    public function when($concrete){}

    public function factory($abstract){}

    public function make($abstract){
    	if(isset($this->instance[$abstract])){
    		return $this->instance[$abstract];
    	}
    	if($this->bindings[$abstract]['concrete'] instanceof Closure){
    		$object = $this->bindings[$abstract]['concrete']();
    	}else{
    		$object = $this->bindings[$abstract]['concrete'];
    	}
    	if($this->bindings[$abstract]['shared']){
    		$this->instance[$abstract] = $object;
    	}
    	return $object;
    }

    public function call($callback, array $parameters = [], $defaultMethod = null){}

    public function resolved($abstract){}

    public function resolving($abstract, Closure $callback = null){}

    public function afterResolving($abstract, Closure $callback = null){}
}

echo '<pre>';
$container = new Container();
$container->bindIf('db', function(){
	return new DB();
}, true);
$db = $container->make('db');
$container->extend('db', function($instance, $container){
    $instance->container = $container;
    print_r($instance);
});
2. Laravel 中如何实现 DI(依赖注入)
    /**
     * Get all dependencies for a given method.
     *
     * @param  \Illuminate\Container\Container
     * @param  callable|string  $callback
     * @param  array  $parameters
     * @return array
     */
    protected static function getMethodDependencies($container, $callback, array $parameters = [])
    {
        $dependencies = [];

        foreach (static::getCallReflector($callback)->getParameters() as $parameter) {
            static::addDependencyForCallParameter($container, $parameter, $parameters, $dependencies);
        }

        return array_merge($dependencies, $parameters);
    }

    /**
     * Get the proper reflection instance for the given callback.
     *
     * @param  callable|string  $callback
     * @return \ReflectionFunctionAbstract
     */
    protected static function getCallReflector($callback)
    {
        if (is_string($callback) && strpos($callback, '::') !== false) {
            $callback = explode('::', $callback);
        }

        return is_array($callback)
                        ? new ReflectionMethod($callback[0], $callback[1])
                        : new ReflectionFunction($callback);
    }

    /**
     * Get the dependency for the given call parameter.
     *
     * @param  \Illuminate\Container\Container  $container
     * @param  \ReflectionParameter  $parameter
     * @param  array  $parameters
     * @param  array  $dependencies
     * @return mixed
     */
    protected static function addDependencyForCallParameter($container, $parameter,
                                                            array &$parameters, &$dependencies)
    {
        if (array_key_exists($parameter->name, $parameters)) {
            $dependencies[] = $parameters[$parameter->name];

            unset($parameters[$parameter->name]);
        } elseif ($parameter->getClass()) {
            $dependencies[] = $container->make($parameter->getClass()->name);
        } elseif ($parameter->isDefaultValueAvailable()) {
            $dependencies[] = $parameter->getDefaultValue();
        }
    }
getCallReflector - 建立对所调函数的反射。
getMethodDependencies/addDependencyForCallParameter - 利用识别所调函数的依赖,从IoC容器中构建这些依赖。
    /**
     * Call the given Closure / class@method and inject its dependencies.
     *
     * @param  \Illuminate\Container\Container  $container
     * @param  callable|string  $callback
     * @param  array  $parameters
     * @param  string|null  $defaultMethod
     * @return mixed
     */
    public static function call($container, $callback, array $parameters = [], $defaultMethod = null)
    {
        if (static::isCallableWithAtSign($callback) || $defaultMethod) {
            return static::callClass($container, $callback, $parameters, $defaultMethod);
        }

        return static::callBoundMethod($container, $callback, function () use ($container, $callback, $parameters) {
            return call_user_func_array(
                $callback, static::getMethodDependencies($container, $callback, $parameters)
            );
        });
    }
call_user_func_array - 将依赖注入到所调函数。
如此,我们可以在 NewsController@addNews 中指定需要的依赖。 public function addNews(Request $request){}

2. Application Object
下面是 bootstrap/app.php return 时的 $app 结构:(第215行即为上述的 Request $request 依赖)
$app = new Illuminate\Foundation\Application{
    'basePath' => 'C:\cygwin64\home\fe\laravel',
    'hasBeenBootstrapped' => '',
    'booted' => '',
    'bootingCallbacks' => [],
    'bootedCallbacks' => [],
    'terminatingCallbacks' => [],
    'deferredServices' => [],
    'monologConfigurator' => '',
    'databasePath' => '',
    'storagePath' => '',
    'environmentPath' => '', 
    'environmentFile' => '.env',
    'namespace' => '',
    'resolved' => [],
    'extenders' => [],
    'tags' => [],
    'buildStack' => [],
    'with' => [],
    'contextual' => [],
    'reboundCallbacks' => [],
    'globalResolvingCallbacks' => [],
    'globalAfterResolvingCallbacks' => [],
    'resolvingCallbacks' => [],
    'afterResolvingCallbacks' => [],
    'methodBindings' => [],
    'serviceProviders' => [
        new Illuminate\Events\EventServiceProvider{
            'app' => {{this}}
            'defer' => '',
        },
        new Illuminate\Log\LogServiceProvider{
                'app' => {{this}}
                'defer' => '',
        },
        new Illuminate\Routing\RoutingServiceProvider{
                'app' => {{this}}
                'defer' => '',
        },
    ]
    'loadedProviders' => [
        'Illuminate\Events\EventServiceProvider'    => '1',
        'Illuminate\Log\LogServiceProvider'         => '1',
        'Illuminate\Routing\RoutingServiceProvider' => '1',
    ],
    'bindings' => [
        'events' => [
            'concrete' => new Closure{
                'this' => new Illuminate\Events\EventServiceProvider{
                    'app' => {{this}},
                    'defer' => '',
                },
                'parameter' => ['$app' => ''],
            },
            'shared' => '1',
        ],
        'log' => [
            'concrete' => new Closure{
                'this' => new Illuminate\Log\LogServiceProvider{
                    'app' => {{this}},
                    'defer' => '',
                },
            },
            'shared' => 1,
        ],
        'router' =>[
            'concrete' => new Closure{
                'this' => new Illuminate\Routing\RoutingServiceProvider{
                    'app' => {{this}},
                    'defer' => '',
                },
                'parameter' => ['$app' => ''],
            },
            'shared' => 1
        ],
        'url' => [
            'concrete' => new Closure{
                'this' => new Illuminate\Routing\RoutingServiceProvider{
                    'app' => {{this}}.
                    'defer' => '',
                },
                'parameter' => ['$app' => ''],
            },
            'shared' => 1
        ],
        'redirect' => [
            'concrete' => new Closure{
                'this' => new Illuminate\Routing\RoutingServiceProvider{
                    'app' => {{this}},
                    'defer' => '',
                },
                'parameter' => ['$app' => ''],
            }
            'shared' => 1
        ],
        'Psr\Http\Message\ServerRequestInterface' => [
            'concrete' => new Closure{
                'this' => new Illuminate\Routing\RoutingServiceProvider{
                    'app' => {{this}},
                    'defer' => '',
                },
                'parameter' => ['$app' => ''],
            }
            'shared' => 
        ],
        'Psr\Http\Message\ResponseInterface' =>[
            'concrete' => new Closure{
                'this' => new Illuminate\Routing\RoutingServiceProvider{
                    'app' => {{THIS}},
                    'defer' => '',
                },
                'parameter' => ['$app' => ''],
            }
            'shared' => 
        ],
        'Illuminate\Contracts\Routing\ResponseFactory' =>[
            'concrete' => new Closure{
                'this' => mew Illuminate\Routing\RoutingServiceProvider{
                    'app' => {{THIS}},
                    'defer' => '',
                },
                'parameter' => ['$app' => ''],
            }
            'shared' => 1
        ],
        'Illuminate\Contracts\Http\Kernel' => [
            'concrete' => new Closure{
                'static' => Array(
                    'abstract' => 'Illuminate\Contracts\Http\Kernel',
                    'concrete' => 'App\Http\Kernel',
                )
                'this' => {{THIS}},
                'parameter' => ['$container' => '', '$parameters' => ''],
            },
            'shared' => 1
        ],
        'Illuminate\Contracts\Debug\ExceptionHandler' => [
            'concrete' => new Closure{
                'static' => [
                    'abstract' => 'Illuminate\Contracts\Debug\ExceptionHandler',
                    'concrete' => 'App\Exceptions\Handler',
                ],
                'this' => {{this}},
                'parameter' =>['$container' => '', '$parameters' => ''],
            },
            'shared' => '1',
        ],
    ],
    'instances' => [
        'path'          => 'C:\cygwin64\home\fe\laravel\app',
        'path.base'     => 'C:\cygwin64\home\fe\laravel',
        'path.lang'     => 'C:\cygwin64\home\fe\laravel\resources\lang',
        'path.config'   => 'C:\cygwin64\home\fe\laravel\config',
        'path.public'   => 'C:\cygwin64\home\fe\laravel\public',
        'path.storage'  => 'C:\cygwin64\home\fe\laravel\storage',
        'path.database' => 'C:\cygwin64\home\fe\laravel\database',
        'path.resources'    => 'C:\cygwin64\home\fe\laravel\resources',
        'path.bootstrap'    => 'C:\cygwin64\home\fe\laravel\bootstrap',
        'Illuminate\Container\Container'    => {{this}},
    ],
    'aliases' => [
        'Illuminate\Foundation\Application'                 => 'app',
        'Illuminate\Contracts\Container\Container'          => 'app',
        'Illuminate\Contracts\Foundation\Application'       => 'app',
        'Illuminate\Routing\UrlGenerator'                   => 'url',
        'Illuminate\Contracts\Routing\UrlGenerator'         => 'url',
        'Illuminate\Validation\Factory'                     => 'validator',
        'Illuminate\Contracts\Validation\Factory'           => 'validator',
        'Illuminate\Auth\AuthManager'                       => 'auth',
        'Illuminate\Contracts\Auth\Factory'                 => 'auth',
        'Illuminate\Contracts\Auth\Guard'                   => 'auth.driver',
        'Illuminate\Auth\Passwords\PasswordBrokerManager'   => 'auth.password',
        'Illuminate\Contracts\Auth\PasswordBrokerFactory'   => 'auth.password',
        'Illuminate\Auth\Passwords\PasswordBroker'          => 'auth.password.broker',
        'Illuminate\Contracts\Auth\PasswordBroker'          => 'auth.password.broker',
        'Illuminate\Cache\CacheManager'                     => 'cache',
        'Illuminate\Contracts\Cache\Factory'                => 'cache',
        'Illuminate\Cache\Repository'                       => 'cache.store',
        'Illuminate\Contracts\Cache\Repository'             => 'cache.store',
        'Illuminate\Session\SessionManager'                 => 'session',
        'Illuminate\Session\Store'                          => 'session.store',
        'Illuminate\Contracts\Session\Session'              => 'session.store',
        'Illuminate\Cookie\CookieJar'                       => 'cookie',
        'Illuminate\Contracts\Cookie\Factory'               => 'cookie',
        'Illuminate\Contracts\Cookie\QueueingFactory'       => 'cookie',
        'Illuminate\Log\Writer'                             => 'log',
        'Illuminate\Contracts\Logging\Log'                  => 'log',
        'Psr\Log\LoggerInterface'                           => 'log',
        'Illuminate\Redis\RedisManager'                     => 'redis',
        'Illuminate\Contracts\Redis\Factory'                => 'redis',
        'Illuminate\View\Factory'                           => 'view',
        'Illuminate\Contracts\View\Factory'                 => 'view',
        'Illuminate\Mail\Mailer'                            => 'mailer',
        'Illuminate\Contracts\Mail\Mailer'                  => 'mailer',
        'Illuminate\Contracts\Mail\MailQueue'               => 'mailer',
        'Illuminate\Config\Repository'                      => 'config',
        'Illuminate\Contracts\Config\Repository'            => 'config',
        'Illuminate\Encryption\Encrypter'                   => 'encrypter',
        'Illuminate\Contracts\Encryption\Encrypter'         => 'encrypter',
        'Illuminate\Database\DatabaseManager'               => 'db',
        'Illuminate\Database\Connection'                    => 'db.connection',
        'Illuminate\Database\ConnectionInterface'           => 'db.connection',
        'Illuminate\Filesystem\Filesystem'                  => 'files',
        'Illuminate\Filesystem\FilesystemManager'           => 'filesystem',
        'Illuminate\Contracts\Filesystem\Factory'           => 'filesystem',
        'Illuminate\View\Compilers\BladeCompiler'           => 'blade.compiler',
        'Illuminate\Events\Dispatcher'                      => 'events',
        'Illuminate\Contracts\Events\Dispatcher'            => 'events',
        'Illuminate\Contracts\Filesystem\Filesystem'        => 'filesystem.disk',
        'Illuminate\Contracts\Filesystem\Cloud'             => 'filesystem.cloud',
        'Illuminate\Contracts\Hashing\Hasher'               => 'hash',
        'Illuminate\Translation\Translator'                 => 'translator',
        'Illuminate\Contracts\Translation\Translator'       => 'translator',
        'Illuminate\Routing\Redirector'                     => 'redirect',
        'Illuminate\Http\Request'                           => 'request',
        'Symfony\Component\HttpFoundation\Request'          => 'request',
        'Illuminate\Routing\Router'                         => 'router',
        'Illuminate\Contracts\Routing\Registrar'            => 'router',
        'Illuminate\Contracts\Routing\BindingRegistrar'     => 'router',
        'Illuminate\Queue\QueueManager'                         => 'queue',
        'Illuminate\Contracts\Queue\Factory'                    => 'queue',
        'Illuminate\Contracts\Queue\Monitor'                    => 'queue',
        'Illuminate\Contracts\Queue\Queue'                      => 'queue.connection',
        'Illuminate\Queue\Failed\FailedJobProviderInterface'    => 'queue.failer',
    ],
    'abstractAliases' => [
        'app'       => ['Illuminate\Foundation\Application', 'Illuminate\Contracts\Container\Container', 'Illuminate\Contracts\Foundation\Application'],
        'auth'      => ['Illuminate\Auth\AuthManager', 'Illuminate\Contracts\Auth\Factory'],
        'cache'     => ['Illuminate\Cache\CacheManager', 'Illuminate\Contracts\Cache\Factory'],
        'config'    => ['Illuminate\Config\Repository', 'Illuminate\Contracts\Config\Repository'],
        'cookie'    => ['Illuminate\Cookie\CookieJar', 'Illuminate\Contracts\Cookie\Factory', 'Illuminate\Contracts\Cookie\QueueingFactory'],
        'db'        => ['Illuminate\Database\DatabaseManager'],
        'files'     => ['Illuminate\Filesystem\Filesystem'],
        'events'    => ['Illuminate\Events\Dispatcher', 'Illuminate\Contracts\Events\Dispatcher'],
        'hash'      => ['Illuminate\Contracts\Hashing\Hasher'],
        'log'       => ['Illuminate\Log\Writer', 'Illuminate\Contracts\Logging\Log', 'Psr\Log\LoggerInterface'],
        'mailer'    => ['Illuminate\Mail\Mailer', 'Illuminate\Contracts\Mail\Mailer', 'Illuminate\Contracts\Mail\MailQueue'],
        'queue'     => ['Illuminate\Queue\QueueManager', 'Illuminate\Contracts\Queue\Factory', 'Illuminate\Contracts\Queue\Monitor'],
        'redis'     => ['Illuminate\Redis\RedisManager', 'Illuminate\Contracts\Redis\Factory'],
        'request'   => ['Illuminate\Http\Request', 'Symfony\Component\HttpFoundation\Request'],
        'router'    => ['Illuminate\Routing\Router', 'Illuminate\Contracts\Routing\Registrar', 'Illuminate\Contracts\Routing\BindingRegistrar'],
        'session'   => ['Illuminate\Session\SessionManager'],
        'redirect'  => ['Illuminate\Routing\Redirector'],
        'url'       => ['Illuminate\Routing\UrlGenerator', 'Illuminate\Contracts\Routing\UrlGenerator'],
        'view'      => ['Illuminate\View\Factory', 'Illuminate\Contracts\View\Factory'],
        'validator'     => ['Illuminate\Validation\Factory', 'Illuminate\Contracts\Validation\Factory'],
        'queue.failer'  => ['Illuminate\Queue\Failed\FailedJobProviderInterface'],
        'encrypter'     => ['Illuminate\Encryption\Encrypter', 'Illuminate\Contracts\Encryption\Encrypter'],
        'auth.driver'   => ['Illuminate\Contracts\Auth\Guard',],
        'cache.store'   => ['Illuminate\Cache\Repository', 'Illuminate\Contracts\Cache\Repository'],
        'session.store' => ['Illuminate\Session\Store', 'Illuminate\Contracts\Session\Session'],
        'translator'    => ['Illuminate\Translation\Translator', 'Illuminate\Contracts\Translation\Translator'],
        'auth.password' => ['Illuminate\Auth\Passwords\PasswordBrokerManager', 'Illuminate\Contracts\Auth\PasswordBrokerFactory'],
        'db.connection' => ['Illuminate\Database\Connection', 'Illuminate\Database\ConnectionInterface'],
        'filesystem'    => ['Illuminate\Filesystem\FilesystemManager', 'Illuminate\Contracts\Filesystem\Factory'],
        'blade.compiler'    => ['Illuminate\View\Compilers\BladeCompiler'],
        'filesystem.disk'   => ['Illuminate\Contracts\Filesystem\Filesystem'],
        'filesystem.cloud'  => ['Illuminate\Contracts\Filesystem\Cloud'],
        'queue.connection'  => ['Illuminate\Contracts\Queue\Queue'],
        'auth.password.broker'  => ['Illuminate\Auth\Passwords\PasswordBroker', 'Illuminate\Contracts\Auth\PasswordBroker'],
    ],
};
4. 给出一些深入理解 IoC 和 DI 的文章
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值