删除 get_ 和 set_ 方法只是一个起点。要创建完全动态的数据库对象,必须向类提供表和字段的名称,还不能有硬编码的引用。清单 5 显示了这个变化。
清单 5. 完全动态的数据库对象类- <?php
- require_once("DB.php");
- $dsn = 'mysql://root:password@localhost/bookdb';
- $db =& DB::Connect( $dsn, array() );
- if (PEAR::isError($db)) { die($db->getMessage()); }
- class DBObject
- {
- private $id = 0;
- private $table;
- private $fields = array();
- function __construct( $table, $fields )
- {
- $this->table = $table;
- foreach( $fields as $key )
- $this->fields[ $key ] = null;
- }
- function __call( $method, $args )
- {
- if ( preg_match( "/set_(.*)/", $method, $found ) )
- {
- if ( array_key_exists( $found[1], $this->fields ) )
- {
- $this->fields[ $found[1] ] = $args[0];
- return true;
- }
- }
- else if ( preg_match( "/get_(.*)/", $method, $found ) )
- {
- if ( array_key_exists( $found[1], $this->fields ) )
- {
- return $this->fields[ $found[1] ];
- }
- }
- return false;
- }
- function load( $id )
- {
- global $db;
- $res = $db->query(
- "SELECT * FROM ".$this->table." WHERE ".
- $this->table."_id=?",
- array( $id )
- );
- $res->fetchInto( $row, DB_FETCHMODE_ASSOC );
- $this->id = $id;
- foreach( array_keys( $row ) as $key )
- $this->fields[ $key ] = $row[ $key ];
- }
- function insert()
- {
- global $db;
- $fields = $this->table."_id, ";
- $fields .= join( ", ", array_keys( $this->fields ) );
- $inspoints = array( "0" );
- foreach( array_keys( $this->fields ) as $field )
- $inspoints []= "?";
- $inspt = join( ", ", $inspoints );
- $sql = "INSERT INTO ".$this->table." ( $fields )
- VALUES ( $inspt )";
- $values = array();
- foreach( array_keys( $this->fields ) as $field )
- $values []= $this->fields[ $field ];
- $sth = $db->prepare( $sql );
- $db->execute( $sth, $values );
- $res = $db->query( "SELECT last_insert_id()" );
- $res->fetchInto( $row );
- $this->id = $row[0];
- return $row[0];
- }
- function update()
- {
- global $db;
- $sets = array();
- $values = array();
- foreach( array_keys( $this->fields ) as $field )
- {
- $sets []= $field.'=?';
- $values []= $this->fields[ $field ];
- }
- $set = join( ", ", $sets );
- $values []= $this->id;
- $sql = 'UPDATE '.$this->table.' SET '.$set.
- ' WHERE '.$this->table.'_id=?';
- $sth = $db->prepare( $sql );
- $db->execute( $sth, $values );
- }
- function delete()
- {
- global $db;
- $sth = $db->prepare(
- 'DELETE FROM '.$this->table.' WHERE '.
- $this->table.'_id=?'
- );
- $db->execute( $sth,
- array( $this->id ) );
- }
- function delete_all()
- {
- global $db;
- $sth = $db->prepare( 'DELETE FROM '.$this->table );
- $db->execute( $sth );
- }
- }
- $book = new DBObject( 'book', array( 'author',
- 'title', 'publisher' ) );
- $book->delete_all();
- $book->set_title( "PHP Hacks" );
- $book->set_author( "Jack Herrington" );
- $book->set_publisher( "O'Reilly" );
- $id = $book->insert();
- echo ( "New book id = $id\n" );
- $book->set_title( "Podcasting Hacks" );
- $book->update();
- $book2 = new DBObject( 'book', array( 'author',
- 'title', 'publisher' ) );
- $book2->load( $id );
- echo( "Title = ".$book2->get_title()."\n" );
- $book2->delete( );
- ? >
-
复制代码 在这里,把类的名称从 Book 改成 DBObject。然后,把构造函数修改成接受表的名称和表中字段的名称。之后,大多数变化发生在类的方法中,过去使用一些硬编码结构化查询语言(SQL),现在则必须用表和字段的名称动态地创建 SQL 字符串。
代码的惟一假设就是只有一个主键字段,而且这个字段的名称是表名加上 _id。所以,在 book 表这个示例中,有一个主键字段叫做 book_id。主键的命名标准可能不同;如果这样,需要修改代码以符合标准。
这个类比最初的 Book 类复杂得多。但是,从类的客户的角度来看,这个类用起来仍很简单。也就是说,我认为这个类能更简单。具体来说,我不愿意每次创建图书的时候都要指定表和字段的名称。如果我四处拷贝和粘贴这个代码,然后修改了 book 表的字段结构,那么我可能就麻烦了。在清单 6 中,通过创建一个继承自 DBObject 的简单 Book 类,我解决了这个问题。
清单 6. 新的 Book 类- ..
- class Book extends DBObject
- {
- function __construct()
- {
- parent::__construct( 'book',
- array( 'author', 'title', 'publisher' ) );
- }
- }
- $book = new Book( );
- $book->delete_all();
- $book->{'title'} = "PHP Hacks";
- $book->{'author'} = "Jack Herrington";
- $book->{'publisher'} = "O'Reilly";
- $id = $book->insert();
- echo ( "New book id = $id\n" );
- $book->{'title'} = "Podcasting Hacks";
- $book->update();
- $book2 = new Book( );
- $book2->load( $id );
- echo( "Title = ".$book2->{'title'}."\n" );
- $book2->delete( );
- ?>
-
复制代码 现在,Book 类真的是简单了。而且 Book 类的客户也不再需要知道表或字段的名称了。 |