객체 관계형 매핑(ORM)은 객체지향 데이터베이스와 관계형 데이터베이스 간의 불일치를 해결하기 위해 고안된 기술입니다. 간단히 말해서 ORM은 개체와 데이터베이스 간의 매핑을 설명하는 메타데이터를 사용하여 프로그램의 개체를 관계형 데이터베이스에 자동으로 유지합니다. 본질적으로 데이터를 한 형식에서 다른 형식으로 변환합니다.
ORM은 모든 SQL 문 생성을 제공하며 코더는 데이터베이스 개념과 거리가 멀습니다. 개념적 요구사항(예: HQL)을 SQL 문으로 매핑하는 데에는 비용이 전혀 들지 않으며 성능 손실도 1%도 없습니다. 실제 성능 저하는 매핑 프로세스 중, 특히 개체 인스턴스화 중에 발생합니다.
현재 가장 유명한 PHP 오픈 소스 ORM은 다음과 같습니다.
1.Propel
Propel은 PHP5에 적합한 ORM 매핑(객체 관계형 매핑) 프레임워크입니다. Apache Torque를 기반으로 객체 지속성 계층 지원을 제공합니다. XML 형식의 스키마 정의 파일과 해당 구성 파일을 통해 SQL과 클래스를 생성합니다. 이를 통해 SQL 대신 개체를 사용하여 데이터베이스 테이블의 레코드를 읽고 쓸 수 있습니다. Propel은 데이터 모델에 대한 SQL 정의 파일과 PHP 클래스를 생성하는 생성기를 제공합니다. 개발자는 생성된 클래스를 쉽게 사용자 정의할 수도 있습니다. 또한 XML, PHP 클래스 및 Phing 빌드 도구를 통해 Propel을 기존 애플리케이션 개발 프레임워크에 통합할 수도 있습니다. 예를 들어, PHP 프레임워크 심포니 1.2 이전 버전은 기본적으로 간소화된 버전입니다. 기본 ORM 프레임워크 역할을 합니다.
공식 웹사이트: http://www.propelorm.org/
2. Doctrine
Doctrine은 PHP ORM 프레임워크이며 >=php5 .2.3에서 실행되어야 합니다. 버전에서는 강력한 데이터 추상화 계층입니다.
주요 기능 중 하나는 데이터베이스 쿼리 클로저를 구현하기 위해 객체 지향 접근 방식을 사용한다는 것입니다. 하위 계층에서는 Hibernate HQL과 유사한 DQL 쿼리 문을 사용하여 데이터베이스 쿼리를 수행하므로 개발이 더욱 유연해집니다. 중복 코드가 줄어듭니다. Propel과 비교할 때 Doctrine의 장점은 전체 텍스트 검색을 지원한다는 것입니다. Doctrine의 문서는 항상 Propel보다 더 포괄적이고 풍부하며 커뮤니티가 더 활동적이며 더 자연스럽고 읽기 쉽고 기본 SQL에 더 가깝습니다. . 성능도 프로펠보다 조금 더 좋습니다. 마찬가지로 Doctrine을 기존 애플리케이션 프레임워크에 쉽게 통합할 수 있습니다. 예를 들어 PHP 프레임워크 심포니 및 이후 버전에서는 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 개발 프레임워크는 Zend Framework를 기반으로 ORM 구현을 구현합니다. SQL 문의 캡슐화 외에도 TableGateway, TableRowSet 및 TableRow의 구현도 구현합니다. Rails의 ActiveRecord 구현과 유사한 몇 가지 솔루션도 있습니다.
일반적으로 일반 ORM 프레임워크는 간단한 응용 시스템의 기본 요구 사항을 충족할 수 있으므로 개발 난이도를 크게 줄이고 개발 효율성을 향상시킬 수 있습니다. 그러나 SQL 최적화 측면에서는 확실히 순수한 SQL 언어보다 나쁩니다. 복잡한 관계 및 SQL 포함 표현식 처리는 이상적이지 않을 수 있습니다. 아마도 이는 주로 PHP 자체의 객체 지속성 문제로 인해 ORM이 너무 비효율적이고 일반적으로 순수 SQL보다 느리기 때문일 것입니다. 그러나 이를 해결할 수 있는 방법이 있습니다. 성능에 대한 가장 기본적인 해결책은 캐싱을 통해 효율성을 높일 수 있다는 것입니다. Hibernate의 경우 구성이 복잡하지만 2차 캐시와 쿼리 캐시를 유연하게 사용하여 문제를 크게 완화합니다. 데이터베이스의 쿼리 압력은 시스템 성능을 크게 향상시킵니다.
PHP ORM을 직접 구현하고 싶다면 다음을 참고하세요.
<?php abstract 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); ?>