目錄
- 目錄
- 前言
- TP5中的select方法
- 爲什麼可以這麼操作
- 總結
- 思考
前言
在使用TP5的過程中,我們會發現,使用select方法查詢數據庫中的數據後dump出來的結果是對應模型的對象。其中該對象有一個protected的data屬性。而在TP3中select出來的結果返回的是一個數組。那麼我們在使用TP5中select後得到了對應的結果——一個對象,怎麼通過這個對象獲取結果數據呢?
結果是同樣可以以數組的方式獲取數據。同TP3的操作。在模板輸出中,同樣也使用。那爲什麼呢?明明這個是一個對象不是什麼數組呀,怎麼可以以數組的方式訪問結果集呢額?
參考:PHP中__get()和__set()的用法實例詳解
PHP實現對象屬性按數組方式訪問
TP5中的select方法
【栗子】調用model創建Goods對應的模型,並使用select方法查詢數據,將查詢結果dump出來,如下:
public function test() {
dump(model('Goods')->select());
}
運行結果如下:
這裏可以看到它返回了一個數組,每個元素的值是一個Goods對象(它繼承於Model類)。可以發現其protected的data屬性保存着我們想要的結果集。我們獲取結果集中的內容,同操作數組無異。如:
public function test() {
//dump(model('Goods')->select());
$res = model('Goods')->select();
$goods = $res[0];
echo 'id:' . $goods['id'] . '<br/>';
echo 'name:' . $goods['name'] . '<br/>';
echo 'brief:' . $goods['brief'] . '<br/>';
}
運行結果如下:
爲什麼可以這麼操作
既然select方法返回的對象繼承於Model類,那其中的玄機一定來自這個Model類。
(可以先閱讀一下,我上面提及的參考文正。)
首先,我們應該考慮,爲什麼一個對象可以以數組的形式訪問。(要是一般情況下,這樣去操作一個對象會報錯的。)
扣一個Model類的源碼,我們會發現Model實現了ArrayAccess接口,恰恰這就是奇妙的地方所在。實現了該接口,並實現了對象的抽象方法,那麼對象就可以以數組形式訪問對象內保存的某些數據。
Model類型實現ArrayAccess接口中的方法,如下:
// ArrayAccess
public function offsetSet($name, $value)
{
$this->setAttr($name, $value);
}
public function offsetExists($name)
{
return $this->__isset($name);
}
public function offsetUnset($name)
{
$this->__unset($name);
}
public function offsetGet($name)
{
return $this->getAttr($name);
}
我們這裏先只考慮獲取屬性值,那麼offsetGet方法就實現了 obj[′key′]獲取值的功能。offsetGet方法中的參數obj[′key′]獲取值的功能。offsetGet方法中的參數name,即以數組操作時傳入的鍵的值。
getArr的實現如下:
/**
* 獲取器 獲取數據對象的值
* @access public
* @param string $name 名稱
* @return mixed
* @throws InvalidArgumentException
*/
public function getAttr($name)
{
try {
$notFound = false;
$value = $this->getData($name);
} catch (InvalidArgumentException $e) {
$notFound = true;
$value = null;
}
// 檢測屬性獲取器
$method = 'get' . Loader::parseName($name, 1) . 'Attr';
if (method_exists($this, $method)) {
$value = $this->$method($value, $this->data);
} elseif (isset($this->type[$name])) {
// 類型轉換
$value = $this->readTransform($value, $this->type[$name]);
} elseif ($notFound) {
$method = Loader::parseName($name, 1);
if (method_exists($this, $method) && !method_exists('\think\Model', $method)) {
// 不存在該字段 獲取關聯數據
$value = $this->relation()->getRelation($method);
// 保存關聯對象值
$this->data[$name] = $value;
} else {
throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
}
}
return $value;
}
在getAttr方法中中主要獲取值的方法又是getData方法。
getData方法如下:
/**
* 獲取對象原始數據 如果不存在指定字段返回false
* @access public
* @param string $name 字段名 留空獲取全部
* @return mixed
* @throws InvalidArgumentException
*/
public function getData($name = null)
{
if (is_null($name)) {
return $this->data;
} elseif (array_key_exists($name, $this->data)) {
return $this->data[$name];
} else {
throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
}
}
TMD發現了!!!getData方法返回的便是當前對象data屬性對應的值。
總結
在這個過程中,最爲關鍵的是Model類實現ArrayAccess接口。通過實現接口的方法,select出來的結果對象便可以通過數組的形式訪問到我們想要的結果集,即對象的protected的data屬性的內容。
思考
TP5中,在使用繼承於Model的模型對象時,會經常發現,我們會使用到如:$model->id
的形式訪問屬性值,可是我們並沒有在對應的模型類聲明id屬性呀。
同樣地,玄機還是在於這個Model類。它含有__get、__set這樣兩個魔術方法:
/**
* 修改器 設置數據對象的值
* @access public
* @param string $name 名稱
* @param mixed $value 值
* @return void
*/
public function __set($name, $value)
{
$this->setAttr($name, $value);
}
/**
* 獲取器 獲取數據對象的值
* @access public
* @param string $name 名稱
* @return mixed
*/
public function __get($name)
{
return $this->getAttr($name);
}
那麼,原因我想你應該知道了。嘻嘻~