ServiceLocator 的作用(之一)是使得访问服务跟组件就像访问类的属性一样。
比如预装代码SiteController.php中的actionLogin方法
if ($model->load(Yii::$app->request->post()) && $model->login()) {
代码中访问request服务是这样的:Yii::$app->request,就好像request是 Yii::$app的一个属性。其实不是的。
单步调试一下代码,会发现执行Yii::$app->request这个代码之后是访问 ServiceLocator.php 的__get方法,为什么会访问这个__get方法呢?
1、Yii::$app 是yii\web\Application的实例,但是实例可见(public, private)属性中并没有request。
2、因此自动调用yii\web\Application的__get方法来查看私有属性中是不是有request
3、可是yii\web\Application类中并没有__get,于是去父类找
4、终于在serviceLocator类中找到了__get, 所以就调用这个__get咯。
接下去呢?
5、__get调用$this->has判断 $this->_definitions['request'] 是否定义
6、如果定义了,那么就调用$this->get()方法
public function get($id, $throwException = true)
{
// 如果$this->_components['request'] 已经定义了
// 就返回$this->_components['request']
if (isset($this->_components[$id])) {
return $this->_components[$id];
}
if (isset($this->_definitions[$id])) {
$definition = $this->_definitions[$id];
if (is_object($definition) && !$definition instanceof Closure) {
return $this->_components[$id] = $definition;
} else {
return $this->_components[$id] = Yii::createObject($definition);
}
} elseif ($throwException) {
throw new InvalidConfigException("Unknown component ID: $id");
} else {
return null;
}
}
7、这样就得到request的实例了,可以调用request 类中的post方法了。Yii::$app->request->post()