對象關係映射(Object Relational Mapping,簡稱ORM)是一種為瞭解決物件導向與關聯式資料庫存在的互不匹配的現象的技術。 簡單的說,ORM是通過使用描述對象和資料庫之間映射的中繼資料,將程式中的對象自動持久化到關聯式資料庫中。本質上就是將資料從一種形式轉換到另外一種形式。
ORM提供了所有SQL語句的產生,代碼人員遠離了資料庫概念。從一個概念需求(例如一個HQL)映射為一個SQL語句,並不需要什麼代價,連1%的效能損失都沒有。真正的效能損失在映射過程中,更具體地講,是在對象執行個體化的過程中。
目前PHP 開源比較有名的 ORM 有以下幾個:
1、Propel
Propel是一個適用於PHP5的ORM映射(Object Relational Mapping)架構,它基於Apache Torque提供對象持久層支援。它通過XML格式的模式定義檔案和相應的設定檔來產生SQL和類,它允許你使用對象代替SQL來讀寫資料庫表中的記錄。Propel提供一個產生器來為你的資料模型建立SQL定義檔案和PHP類。開發人員也可以十分簡單的定製產生的類,我們還可以通過XML, PHP類和Phing構建工具把Propel整合到已有的應用開發架構中去.例如PHP架構symfony的1.2以前的版本就是預設使用了精簡版的Propel作為預設ORM架構。
官方網站:http://www.propelorm.org/
2、Doctrine
Doctrine是一個PHP的ORM架構,它必須運行在>=php5.2.3版本上,它是一個功能強大的資料抽象層。
它的一個主要特徵就是使用物件導向的方式來實現資料庫查詢的封轉,它底層通過一個類似 Hibernate HQL的DQL的查詢語句進行資料庫查詢,這使得開發的靈活性更強,大大減小了重複代碼。相比Propel,Doctrine的優點在於它支援支援全文檢索索引,Doctrine的文檔一直就比Propel要全面豐富,社區更活躍,而且使用起來更加自然、更易閱讀、更接近原生SQL。效能方面也略微優於Propel。同樣你也可以可以很方便的把Doctrine整合到現有的應用程式框架中去,比如PHP架構symfony的1.3以後的版本將Doctrine作為預設的ORM架構,同時也可以將Doctrine和Codeigniter整合起來。
官方網站: http://www.doctrine-project.org/
3、EZPDO
EZPDO是一個十分輕量級的PHP ORM架構。EZPDO的作者的本意旨在降低複雜的ORM學習曲線,儘可能在ORM的運行效率和功能之間做一個平衡點,它是我至今用過的最簡單的ORM架構,我目前還想將它整合到我的CoolPHP SDK中來,而且運行效率相當不錯,功能也基本能滿足需求,只不過EZPDO的更新比較緩慢。
官方網站:http://www.ezpdo.net/
4、RedBean
RedBean是一個便於使用,輕量級PHP ORM架構,提供對MySQL, SQLite&PostgreSQL的支援。RedBean架構非常靈活,核心也非常簡約,開發人員可以很方便的通過外掛程式來擴充功能。
官方網站:http://www.redbeanphp.com/
5、其他
國內的fleaphp開發架構基於TableDataGateway實現ORM實現;Zend Framework除了提供對 SQL 陳述式的封裝以外,也同樣實現了TableGateway、TableRowSet、TableRow的實現;還有一些類似Rails的ActiveRecord實現的解決方案。
總的來說,一般ORM架構對付簡單的應用系統來說都能滿足基本需求,可以大大降低開發難度,提高開發效率,但是它在SQL最佳化方面,肯定是比純SQL語言要差一些,對複雜關聯、SQL內嵌運算式的處理可能不是很理想。也許這主要是由於PHP本身對象持久化的問題,導致ORM效率過低,普遍比純SQL要慢。但是這些都是有辦法解決的,最基本的解決效能的方案,我們可以通過緩衝來提高效率,Hibernate來說,雖然配置比較繁雜,但是它通過靈活的使用二級緩衝和查詢快取極大的緩解資料庫的查詢壓力,極大的提升了系統的效能。
如果你想自己實現一個PHP的ORM,下面的可以參考下:
<?phpabstract class Model{ protected $pk = 'id'; protected $_ID = null; protected $_tableName; protected $_arRelationMap; protected $_modifyMap; protected $is_load = false; protected $_blForDeletion; protected $_DB; public function __consturct($id = null){ $this->_DB = mysql_connect('127.0.0.1','root','') ; $this->_tableName = $this->getTableName(); $this->_arRelationMap = $this->getRelationMap(); if(isset($id))$this->_ID = $id; } abstract protected function getTableName(); abstract protected function getRelationMap(); public function Load(){ if(isset($this->_ID)){ $sql = "SELECT "; foreach($this->_arRelationMap as $k => $v){ $sql .= '`'.$k.'`,'; } $sql .= substr($sql,0,strlen($sql)-1); $sql .= "FROM ".$this->_tableName." WHERE ".$this->pk." = ".$this->_ID; $result =$this->_DB->mysql_query($sql); foreach($result[0] as $k1 => $v1){ $member = $this->_arRelationMap[$key]; if(property_exists($this,$member)){ if(is_numeric($member)){ eval('$this->'.$member.' = '.$value.';'); }else{ eval('$this->'.$member.' = "'.$value.'";'); } } } } $this->is_load = true; } public function __call($method,$param){ $type = substr($method,0,3); $member = substr($method,3); switch($type){ case 'get': return $this->getMember($member); break; case 'set': return $this->setMember($member,$param[0]); } return false; } public function setMember($key){ if(property_exists($this,$key)){ if(is_numeric($val)){ eval('$this->'.$key.' = '.$val.';'); }else{ eval('$this->'.$key.' = "'.$val.'";'); } $this->_modifyMap[$key] = 1; }else{ return false; } } public function getMember($key,$val){ if(!$this->is_load){ $this->Load(); } if(property_exists($this,$key)){ eval('$res = $this->'.$key.';' ); return $this->$key; } return false; } public function save(){ if(isset($this->_ID)){ $sql = "UPDATE ".$this->_tableName." SET "; foreach($this->arRelationMap as $k2 => $v2){ if(array_key_exists( $k2, $this->_modifyMap)){ eval( '$val = $this->'.$v2.';'); $sql_update .= $v2." = ".$val; } } $sql .= substr($sql_update,0,strlen($sql_update)); $sql .= 'WHERE '.$this->pk.' = '.$this->_ID; }else{ $sql = "INSERT INTO ".$this->_tableName." ("; foreach($this->arRelationMap as $k3 => $v3){ if(array_key_exists( $k3,$this->_modifyMap)){ eval('$val = $this->'.$v3.';'); $field .= "`".$v3."`,"; $values .= $val; } } $fields = substr($field,0,strlen($field)-1); $vals = substr($values,0,strlen($values)-1); $sql .= $fields." ) VALUES (".$vals.")"; } echo $sql; //$this->_DB->query($sql); } public function __destory(){ if(isset($this->ID)){ $sql = "DELETE FROM ".$this->_tableName." WHERE ".$this->pk." = ".$this->_ID; // $this->_DB_query($sql); } }}class User extends Model{ protected function getTableName(){ return "test_user"; } protected function getRelationMap(){ return array( 'id' => USER_ID, 'user_name'=> USER_NAME, 'user_age' => USER_AGE ); } public function getDB(){ return $this->_DB; }}$UserIns = new User();print_r($UserIns);?>