繼承樹分析
看yii2框架的源代碼會發(fā)現(xiàn),請求的入口,也就是index.php文件,相當(dāng)?shù)暮唵危谌肟谖募杏幸恍邢铝写a:
(new yii\web\Application($config))->run();
這里面實例化了一個Application類的對象,并調(diào)用了這個對象的run方法,這篇文章要記錄的,就是這個類的來龍去脈。
想要理清這個類具體是干什么的,首先來分析一下這個類的所有父類,這個類的繼承樹如下,
- yii\web\Application
- yii\base\Application
- yii\base\Module
- yii\di\ServiceLocator
- yii\base\Component
- yii\base\Object
- yii\base\Configurable
這個列表后邊的依次是前面的父類。那么現(xiàn)在就從下往上依次研究一下這些類。
yii\base\Configurable
這個類只是一個很簡單的接口,原代碼如下:
interface Configurable
{
}
竟然什么都沒有。。。那么這個類的功能到底是什么呢,通過查看注釋可以看出,這個Configurable接口其實就是定義了一種約定,所有實現(xiàn)這個接口的類都必須滿足一個條件,這個條件就是這個類的構(gòu)造函數(shù)的最后一個參數(shù)是一個配置數(shù)組,其中key為這個類對應(yīng)的屬性,value為屬性對應(yīng)的值。構(gòu)造函數(shù)需要采用如下的形式:
public function __constructor($param1, $param2, ..., $config = []) ```
這個類很簡單,接下來繼續(xù)來看。
## yii\base\Object
先來看一下這個類的方法有哪些:
```php
class Object implements Configurable
{
public static function className()
{
return get_called_class();
}
public function __construct($config = [])
{
if (!empty($config)) {
Yii::configure($this, $config);
}
$this->init();
}
public function init(){
}
public function __get($name)
public function __set($name, $value)
public function __isset($name)
public function __unset($name)
public function __call($name, $params)
public function hasProperty($name, $checkVars = true)
public function canGetProperty($name, $checkVars = true)
public function canSetProperty($name, $checkVars = true)
public function hasMethod($name)
}
其中只有init是個空方法。需要說明一點的是,yii\base\Object這個類提供了yii2框架所采用的一個非常重要的特性:屬性。屬性用來表示對象的狀態(tài),定義一個屬性通常采用如下的方法:
private $_label;//第一步,定義一個private的屬性
public function getLabel() // 設(shè)置get方法,可讀屬性
{
return $this->_label;
}
public function setLabel($value) //設(shè)置set方法,可寫屬性
{
$this->_label = $value;
}
上面是對屬性這個概念進行分析,Object對象是怎么提供這個特性的呢,這里首先要看一下構(gòu)造函數(shù)中的代碼:
Yii::configure($this, $config);
定位到這個函數(shù):
public static function configure($object, $properties)
{
foreach ($properties as $name => $value) {
$object->$name = $value;
}
return $object;
}
看起來好簡單的樣子,遍歷,然后屬性賦值。當(dāng)調(diào)用類不存在的屬性時會調(diào)用魔術(shù)方法,Object類重載了魔術(shù)方法:
public function __set($name, $value)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
$this->$setter($value);
} elseif (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
}
當(dāng)賦值某一個不存在的屬性時會去調(diào)用相應(yīng)的set方法,相應(yīng)的獲取某個屬性的值會調(diào)用get方法。
每個Object子類如果有構(gòu)造方法,在其中一定會調(diào)用父類的構(gòu)造方法,并將property數(shù)組傳遞過去,由此終于知道Object類怎么實現(xiàn)屬性這個特性了。如果我們想要以及編寫的類擁有屬性這個特性,首先需要為每一個屬性設(shè)定相應(yīng)的get和set方法,然后在實例化的時候傳遞一個配置數(shù)組,將這個數(shù)組傳遞到父類的構(gòu)造函數(shù)就行了。所以在入口文件,實例化Application的時候,傳遞了一個$config數(shù)組,里面的key便是這個Application的一個個屬性。
還需要注意的一點就是,在Object的構(gòu)造函數(shù)中,調(diào)用了init方法進行一些初始化,在子類中可以覆蓋這個方法進行一些初始化的操作