`
love~ruby+rails
  • 浏览: 852852 次
  • 性别: Icon_minigender_1
  • 来自: lanzhou
社区版块
存档分类
最新评论

PHP5 Database Iterators <2>

阅读更多

Introducing the Db_Iterator Object

The getCommentList() method in the User class returns a Db_Iterator instance that holds a result set to the list of comments created by that User. getCommentList() uses Lazy Loading, a method to only load up the comments when necessary (i.e., the first time getCommentList() is called, rather than on object construction). Looking at the Db_Iterator object (with kind thanks to the original implementer, Trevor Andreas), one can see that it stores the result object as a private member variable.

<?php
 
/**
 * Creates a new Db Iterator object. Allows for fast and memory efficient
 * handling of a lot of rows that correspond to an object.
 * @author tandreas <tandreas@gmail.com>
 * @author vmc <vmc@leftnode.com>
 */
class Db_Iterator implements Iterator {
  ///< The result set from the database.
  private $_result = NULL;
 
  ///< The object/model that is built on each iteration.
  private $_object = NULL;
 
  ///< The current row.
  private $_key = 0;
 
  /**
   * The default constructor to build a new Iterator.
   * @author tandreas <tandreas@gmail.com>
   * @param $result The result object.
   * @param $object An empty object.
   * @retval Object Returns a new Db_Iterator object.
   */
  public function __construct(Artisan_Db_Result $result, $object) {
    $this->_result = $result;
    $this->_object = $object;
    $this->_key = 0;
  }
 
  /**
   * Destructs the iterator and frees the result set if its not null.
   * @author vmc <vmc@leftnode.com>
   * @retval NULL Returns NULL.
   */
  public function __destruct() {
    $this->_object = NULL;
    if ( NULL !== $this->_result ) {
      $this->_result->free();
      $this->_result = NULL;
    }
  }
 
  /**
   * Destructs the iterator and frees the result set if its not null.
   * @author vmc <vmc@leftnode.com>
   * @param $data Sets the data of the object through loadFromArray().
   * @retval Object Returns the object for easy write access.
   */
  public function set($data) {
    if ( true === is_array($data) ) {
      $this->_object->loadFromArray($data);
    }
    return $this->_object;
  }
 
  /**
   * Returns the current element.
   * @author tandreas <tandreas@gmail.com>
   * @retval Object Returns the current element of the iteration list.
   */
  public function current() {
    return $this->_load($this->_key);
  }
 
  /**
   * Returns the last row.
   * @author tandreas <tandreas@gmail.com>
   * @retval Object Returns the last row.
   */
  public function last() {
    $num_rows = $this->_result->numRows()-1;
    return $this->_load($num_rows);
  }
 
  /**
   * Returns the key of the current element.
   * @author tandreas <tandreas@gmail.com>
   * @retval int Returns the integer key of the current element.
   */
  public function key() {
    return $this->_key;
  }
 
  /**
   * Moves to the next element.
   * @author tandreas <tandreas@gmail.com>
   * @retval int Returns the next key's value.
   */
  public function next() {
    $this->_key++;
    return $this->_key;
  }
 
  /**
   * Rewinds to the first row of the result.
   * @author tandreas <tandreas@gmail.com>
   * @retval boolean Returns true.
   */
  public function rewind() {
    $this->_key = 0;
    $this->_result->row(0);
    return true;
  }
 
  /**
   * Determines if the next() or current() calls are valid.
   * @author tandreas <tandreas@gmail.com>
   * @author vmc <vmc@leftnode.com>
   * @retval bool Returns true if they are valid, false otherwise.
   */
  public function valid() {
    return ( $this->_key != $this->_result->numRows() );
  }
 
  /**
   * Loads up the specified object during iteration.
   * @author vmc <vmc@leftnode.com>
   * @param $i The key/index to load from.
   * @retval Object Returns the built object.
   */
  private function _load($i) {
    $this->_result->row($i);
    $row = $this->_result->fetch();
 
    if ( true === is_array($row) ) {
      $this->_object->loadFromArray($row);
    }
 
    return $this->_object;
  }
}

When initially building this, the largest problem faced was the desire to not have each iteration require a new query to load up that object. To us, that defeated the entire reason for the class as it required a database call on each iteration when a single one could be made instead. The decision to add the set() method, and corresponding loadFromArray() method was made. On each iteration, loadFromArray() is called in _load() to set the data from the row to the object. In turn, loadFromArray() identifies the primary key of the object, id, and the rest of the data as the model. This is a very fast way to load up an object without the use of another query.

In addition to loadFromArray(), set() can be used to add new elements to the list. Because set() returns an instance of the object originally passed into the Db_Iterator instance, one can immediately call write() on the returned object to write it to the datastore. Furthermore, if the $comment_data array has a valid id entry, the object will be updated rather than inserted. This creates a very easy interface for adding and updating new objects from a single point of entry.

Implementation

Testing this implementation is simple and intuitive.

<?php
 
require_once 'Object/LN.php';
require_once 'Object/Model.php';
require_once 'Object/Iterator.php';
require_once 'Object/User.php';
require_once 'Object/Comment.php';
 
require_once 'Artisan/Db/Adapter/Mysqli.php';
require_once 'Artisan/Config/Array.php';
require_once 'Artisan/Functions/Array.php';
 
/**
 * Set up some database configuration data.
 */
$config_db = new Artisan_Config_Array(array(
  'server' => 'localhost',
  'username' => 'username',
  'password' => 'password',
  'database' => 'iterator_test',
  'debug' => false
  )
);
 
LN::init($config_db);
 
/**
 * Create a new User object, and load up all of the comments
 * user ID #1 has made.
 */
$user = new User(1);
$comment_list = $user->getCommentList();
 
/**
 * Loop through all of the comments. $comment is an object of type
 * User_Comment.
 */
foreach ( $comment_list as $comment ) {
  echo $comment . '<br>';
}
 
/**
 * Insert a new comment. $comment_data could easily come from a form submission.
 * If there was a field name 'id' in the array below, and it had a valid ID,
 * the comment would be updated rather than inserted when write() is called.
 */
echo '<br>';
echo 'Adding a new comment....<br>';
$comment_data = array(
  'from_id' => 1,
  'to_id' => 2,
  'comment' => 'thanks for the reply, @joeperry!'
);
$comment_list = $user->getCommentList()->set($comment_data)->write();
 
/**
 * Force a reload of the comments. true must be passed to the method.
 */
echo '<br>';
echo 'Reloading the comments....<br><br>';
$comment_list = $user->getCommentList(true);
 
foreach ( $comment_list as $comment ) {
  echo $comment . '<br>';
}
 
echo '<hr>';
echo round((memory_get_peak_usage()/(1024*1024)), 4) . 'MB';
 
LN::cleanup();

Final Questions

Using this overall solution begs a question: what happens on the datastore’s end when holding a result set in memory during the page execution. Fortunately, not much. The Db_Iterator class handles the result set variable. PHP uses copy-on-write for its variable’s value, and because the result variable is never written to, the variable that’s passed into the Db_Iterator instance is destroyed by the iterator’s destructor.

Conclusion

The initial implementation is very trivial. Further applications exist for the iterator, such as filtering results and easy pagination. Using these methods, developers can quickly and easily manage their objects from a central object. This technique was used extensively in the Prospect Vista project. Similar to this article, a single User object controls many different iterators of children objects the User object had created. For example, one User type can create: Comments, Contacts, Fans, Payments, Statistics, Statuses, and Videos. With this code, loading up a list of Contacts is as simple as: $user->getContactList().

Iterators are a very powerful and surprisingly simple way to reconfigure your application. One can cut down on the amount of SQL queries executed and the total memory used, and clean up the design of their classes with little effort. The code in this article was adopted from Artisan System, Leftnode’s PHP5 framework.

分享到:
评论

相关推荐

    C /C++库函数及文件大全 经典 chm

    各种函数以及库文件的...Ended Queues &lt;br&gt;C++ Lists &lt;br&gt;C++ Priority Queues &lt;br&gt;C++ Queues &lt;br&gt;C++ Stacks &lt;br&gt;C++ Sets &lt;br&gt;C++ Multisets &lt;br&gt;C++ Maps &lt;br&gt;C++ Multimaps &lt;br&gt;C++ Bitsets &lt;br&gt;Iterators &lt;br&gt;

    Visual C++ 编程资源大全(英文源码 网络)

    12.zip&lt;br&gt;Winsock2 Internet functions &lt;br&gt;Winsock 2.0网络函数(5KB)&lt;END&gt;&lt;br&gt;90,13.zip&lt;br&gt;Get hostname and ip address of local computer&lt;br&gt;得到本地计算机的主机名和IP地址(4KB)&lt;END&gt;&lt;br&gt;91,14.zip&lt;br&gt;Mail ...

    The Art of Assembly Language Programming

    The 80x86 MOV Instruction&lt;br&gt;4.8 - Some Final Comments on the MOV Instructions&lt;br&gt;&lt;br&gt;4.9 Laboratory Exercises&lt;br&gt;4.9.1 The UCR Standard Library for 80x86 Assembly Language Programmers&lt;br&gt;4.9.2 ...

    C 标准程序库自修教程与参考手册

    通用工具&lt;br&gt;5.Standard Template Library(STL,标准模板库)&lt;br&gt;6.STL容器(STL Container)&lt;br&gt;7.STL 迭代器(STL Iterators)&lt;br&gt;8.STL 仿函数(functors)(又名函数对象,function objects)&lt;br&gt;9.STL算法...

    Apress.Accelerated.C.Sharp.2008.Nov.2007

    &lt;br&gt; &lt;br&gt; What you'll learn:&lt;br&gt; - How C# works with and exploits the CLR&lt;br&gt; - How to use arrays, collections, and iterators&lt;br&gt; - How to handle events with delegates and anonymous functions&lt;br&gt; - ...

    C++ Standard Library: A Tutorial and Reference

    Input/Output Using Stream Classes&lt;br/&gt;&lt;br/&gt;13.1 Common Background of I/O Streams&lt;br/&gt;&lt;br/&gt;13.2 Fundamental Stream Classes and Objects&lt;br/&gt;&lt;br/&gt;13.3 Standard Stream Operators &lt;&lt; and &gt;&gt;&lt;br/&gt;&lt;br/&gt;13.4 ...

    visual assist v 10.4.1632 with crack

    (case=9436) &lt;br&gt;STL list&lt;&gt; and vector&lt;&gt; member lists appear correctly following a "using namespace std::list" or "using namespace std::vector" directive. (case=12345) 7226 &lt;br&gt;Empty C++ preprocessor ...

    标准模板库STL

    STL容器部分主要由头文件&lt;vector&gt;、&lt;list&gt;、&lt;deque&gt;、&lt;set&gt;、&lt; map&gt;、&lt;stack&gt;和&lt;queue&gt;组成。 (2)算法(Algorithms)。包括各种基本算法,如比较、交换、查找、排序、遍历操作、复制、修改、移除、反转、合并...

    The-C++-Programming-Language(ch 3)

    list&lt;int&gt; numbers = {1, 2, 3, 4, 5}; auto it = numbers.begin(); advance(it, 2); // 移动迭代器到第三个元素 numbers.erase(it); for (int n : numbers) { cout &lt;&lt; n &lt;&lt; " "; } cout &lt;&lt; endl; return...

    C++标准库MSDN离线文档-微软2017-10月发布

    部分内容部分介绍了C++标准库中包含的头文件和功能模块,其中包括了常用的&lt;array&gt;、&lt;iostream&gt;、&lt;string&gt;等,这些都是构建C++程序不可或缺的部分。文档提及了算法(Algorithm)、分配器(Allocators)、迭代器...

    C++标准库和头文件名字

    2. **容器**:这部分在`&lt;vector&gt;`, `&lt;list&gt;`, `&lt;set&gt;`, `&lt;map&gt;`等头文件中定义,提供了一种组织和管理数据的方式。例如,`std::vector`是一个动态数组,而`std::list`则是一个双向链表。 3. **迭代器(Iterators)*...

    C++标准程序库

    std::vector&lt;int&gt; numbers = {1, 2, 3, 4, 5}; std::vector&lt;int&gt;::iterator it; // 输出所有元素 for (it = numbers.begin(); it != numbers.end(); ++it) { std::cout &lt;&lt; *it &lt;&lt; " "; } std::cout &lt;&lt; std::...

    C++标准函数库 C++标准函数库

    2. 标准模板库(STL):STL是C++标准库的核心,包含四个主要组件:算法(algorithms)、容器(containers)、迭代器(iterators)和函数对象(function objects)。例如,`vector`、`list`、`map`等容器提供动态数组、链表和...

    google interview problem of iterator

    public RotateIterator(List&lt;Iterator&lt;T&gt;&gt; iterators) { this.iterators = iterators; } @Override public boolean hasNext() { while (currentIteratorIndex &lt; iterators.size()) { if (iterators.get...

    C程序设计教学课件:chapter6templatePart2.pptx

    - 容器适配器(Container Adapters):例如`&lt;stack&gt;`、`&lt;queue&gt;`和`&lt;priority_queue&gt;`,它们是基于其他容器的特殊版本,提供了特定的操作行为,如先进先出(FIFO)或优先级排序。 3. 迭代器(Iterators): 迭代...

    csv2:适用于Modern C ++的快速CSV解析器和编写器

    目录 CSV阅读器# include &lt; csv2&gt;int main () { csv2::Reader&lt;delimiter&gt;, quote_character&lt; ' " ' &gt;, first_row_is_header&lt; true&gt;, trim_policy::trim_whitespace&gt; csv; if (csv. mmap ( " foo.csv " )) { const...

    C#设计模式迭代器示例

    2. **实现迭代器**:创建一个类,实现 `IEnumerator` 或 `IEnumerator&lt;T&gt;` 接口。你需要实现 `Current` 属性、`MoveNext` 方法和 `Reset` 方法。通常,迭代器还需要一个构造函数,接收聚合对象的引用,以便在迭代...

    sap 操作XML(自己的笔记)

    &lt;LASTNAME&gt;Whitman2&lt;/LASTNAME&gt; &lt;/ITEM&gt; &lt;/ELEMENT&gt; &lt;/ROOTNODE&gt; ``` ##### 2. 解析XML 解析XML是指将XML文档转换为计算机可读的数据结构,以便进行进一步处理。解析XML的方法主要有两种: - **基于DOM ...

    自己写的基于C#的小型健康体检软件

    5. **HashSet&lt;T&gt;**:无序且不允许重复元素的集合,适合快速查找和插入操作。 6. **Dictionary&lt;TKey, TValue&gt;**:键值对集合,用于存储具有唯一键的对象。它提供了快速的查找和访问速度。 7. **Queue&lt;T&gt;**:FIFO...

    C++STL vector list map set dqueue 等应用举例及PPT讲解示例,代码演示

    STL的核心组件包括容器(containers)、迭代器(iterators)、函数对象(functors)和算法(algorithms)。在这个主题中,我们将深入探讨vector、list、map、set和deque这五个主要的STL容器,并通过具体的例子和PPT...

Global site tag (gtag.js) - Google Analytics