第一个common中的service,第二个是fecshop中的service这两种service都被index.php给作为config初始化了。 如图: 试问:比如common->config->fecshop_local_services->Product.php和fecshop -> services->Product.php有什么关联关系?第一个Product.php返回的是第二个php文件的实例吗? 他们会同时存在于$config中吗?
这个是Yii2的容器注入,原理就是:吧一个类和一个配置数据扔给容器,容器给生成一个对象。
配置:common\config\fecshop_local_services\Product.php
common\config\fecshop_local_services\Product.php
类:@fecshop\services\Product.php
容器方法,也就是:Yii::createObject($service);
Yii::createObject($service);
所有的service都继承于 [@fecshop](/member/fecshop)\services\Service 在这个类里面可以看到如下代码:
[@fecshop](/member/fecshop)\services\Service
protected function getChildService($childServiceName) { if (!$this->_childService[$childServiceName]) { $childService = $this->childService; if (isset($childService[$childServiceName])) { $service = $childService[$childServiceName]; $this->_childService[$childServiceName] = Yii::createObject($service); } else { throw new InvalidConfigException('Child Service ['.$childServiceName.'] is not find in '.get_called_class().', you must config it! '); } } return $this->_childService[$childServiceName]; }
原理为使用php的魔术方法 __get() ,在上面的类中你可以看到这个魔术方法调用了 getChildService($childServiceName) , 这个函数里面调用了 Yii::createObject($service); 这个容器函数,来生成相应的对象。
__get()
getChildService($childServiceName)
上面说的就是容器生成的原理,Yii2的组件就是这个原理搞的,按照Yii::$app->xxxxx,进行调用组件,组件是单例模式,
fecshop参考了Yii2组件的原理,Yii::$service->xxxx 的方式调用service
对于每一个service的配置,一共有几个配置文件,在初始化的时候合并
@fecshop//config/services/Product.php : 这个配置文件是yii2对services的默认配置。
@fecshop//config/services/Product.php
@common/config/fecshop_local_services/Product.php :如果你想全局重写Product services , 可以在 这个配置文件中更改配置
@common/config/fecshop_local_services/Product.php
@appfront/config/fecshop_local_services/Product.php :如果你在单个入口重写 Product services,譬如在appfront中重写,您可以在 这个文件中更改配置,如果Product.php不存在,您可以新建一个配置文件。
@appfront/config/fecshop_local_services/Product.php
这三个配置文件是有优先级的,高优先级的配置会覆盖低优先级的配置, @appfront @common [@fecshop ,优先级由高到低,
@appfront
@commo
[@fecshop
原理为:打开@app/web/index.php 可以看到代码:(@app 统称,代指 @appfront @apphtml5等)
@app/web/index.php
@app
@apphtml5
$config = yii\helpers\ArrayHelper::merge( require(__DIR__.'/../../common/config/main.php'), require(__DIR__.'/../../common/config/main-local.php'), require(__DIR__.'/../config/main.php'), require(__DIR__.'/../config/main-local.php'), // fecshop services config require(__DIR__.'/../../vendor/fancyecommerce/fecshop/config/fecshop.php'), // fecshop module config require(__DIR__.'/../../vendor/fancyecommerce/fecshop/app/appfront/config/appfront.php'), // thrid part confing // common modules and services. require(__DIR__.'/../../common/config/fecshop_local.php'), // appadmin local modules and services. require(__DIR__.'/../config/fecshop_local.php') );
也就是配置会在初始化的时候合并,通过yii\helpers\ArrayHelper::merge() 函数合并, 高优先级的会覆盖低优先级的,通过配置覆盖的方式来实现功能的重写。
yii\helpers\ArrayHelper::merge()
还有什么疑问,在下面留言。
这个部分的文档不够完善,回头完善一下。
可以参看这个链接,看一下index.php的初始化工作:http://www.fecshop.com/doc/fecshop-guide/develop/cn-1.0/guide-fecshop-init-index.html
关于fecshop的配置结构的介绍,可以看这个文档:
http://www.fecshop.com/doc/fecshop-guide/instructions/cn-1.0/guide-fecshop_config_construction.html
那么fecshop\services目录下的所有定义的Service类就是所有config目录下中service的描述?不知道我描述的准不准确
好想有点明白了工作的流程了,原理还是不是很懂
@xiaobeibei #5楼 容器注入, 上面写了,根据类和配置,生成一个单例模式的对象,放到Yii::$service的一个属性(这个属性是数组)里面,__get()方法会到这个属性里面取之前生成的对象,取不到就会生成,你先了解下yii框架把。
请问 Terry有相关文章吗?http://www.yiichina.com/tutorial/112 我只找到这个不知是否准确
@xiaobeibei #7楼 知道原理就行了,那个是探究原理的代码
可以很简单的理解原理就行了,譬如:
容器方法:Yii::createObject($service);
容器的作用就是实例化类,生成一个对象,然后利用配置中的数组数据,对对象的属性依次赋值,就这么个原理,如果想了解本质,可以看看你发的那个文章。
谢谢