如果你有扩展过CI的HMVC(hex提供的方案),你可能会在实际使用的过程中越来越理解HMVC,但也可能会越来越搞不清楚什么是HMVC,正如paperen一样…有时候特别觉得模块这个词实在是抽象,到底什么才能定义为模块,到底概念并不是最重要,重要的是你用起来是否合理,是否有效,是否能更好减少耦合。

在paperen使用hex提供的这个hmvc方案过程中,确实也遇到了一些bug,不过目前的已经得到修复,关于hmvc我觉得重要一点是模块之间数据不能共用,而导致一个页面有可能执行了多条一样的SQL,想体现一下这种现象,也很简单。

这是原始调用模型的写法

$this->load->model('userlog_model');
print_r( $this->userlog_model->all() );

调用了userlog_model中的all方法,是什么不要紧,反正你知道这里就是送出一条SQL就够了

而假设我们有两个模块test3,test4,调用各自的test方法都会调用这个模型的这个all方法,现在我在welcome控制器的test方法里面写下这两段,分别调用test3、test4模块的test方法

并输出调试数据

$this->output->enable_profiler();

那么访问该URL后你会看到调试数据

执行了两条一样的sql,当然因为mysql自身有缓存机制所以第二条sql花费的时间小一点,但是毕竟送出两条SQL始终会增加程序等待数据库数据响应的时间,而且说实在其实数据是可以公用的,我们只需要建立一种机制就可以实现,paperen这里直接放出自己这个方案好了,就是引入了一个叫querycache的类,调用模型的方法时也不像原始那样写了

下面是一个使用范例

// querycache
print_r( $this->querycache->get( 'userlog', 'all' ) );
就是这样就已经可以了,不妨对比一下上面的原始写法,使用querycache就更加懒了,不用每次都$this->load->model,querycache会自动给你加载相关的模型


以下为querycache的代码


<?php

/**
 * 作為查詢緩存,避免不同模塊執行相同SQL導致性能下降一個組件
 * 依賴于CI模型
 * @author paperen
 */
class Querycache
{

 private $_CI;
 private $_cache;

 function __construct()
 {
  $this->_CI = & get_instance();
 }

 /**
  * 直接執行模型操作
  * @param string $model_name 模型名
  * @param string $method 方法
  * @param mixed $args 參數
  * @return mixed
  */
 public function execute( $model, $method, $args )
 {
  $model_name = "{$model}_model";
  if ( !isset( $this->_CI->$model_name ) ) $this->_CI->load->model( $model_name );
  return call_user_func_array( array( $this->_CI->$model_name, $method ), $args );
 }

 /**
  *
  * @param string $model 模型名(不需要加_model)
  * @param string $method 方法
  * @return mixed
  */
 public function get( $model, $method )
 {
  // 获取参数数据
  $args = func_get_args();
  $model_and_method = array_shift( $args ) . '_' . array_shift( $args );

  // 索引
  $hash = "{$model_and_method}_" . serialize( $args );

  // 存在缓存直接返回
  if ( isset( $this->_cache[$hash] ) ) return $this->_cache[$hash];

  // 通过模型获取数据
  $result = $this->execute( $model, $method, $args, TRUE );

  // 缓存起来
  $this->_cache[$hash] = $result;
  return $result;
 }

}

// end of Querycache

就是有execute与get两个public的方法,只有使用get才具有查询缓存概念,而execute一般是使用在insert与update的操作,因为更新与插入并不需要缓存起来,只有查询才需要,当将test3、test4模块中的test方法中的查询都改为使用querycache的话,你会看到这个页面只执行了一条SQL

这就是我们想要的效果,不同模块中调用相同模型相同方法相同参数时,就不用重复送同样的SQL了,若曾经执行过的话直接将数据返回就可以了

若模型的方法有多个参数,比如以下这个方法

function all( $per_page = 5, $offset = 0 )
{
 print_r( func_get_args() );
 return $this->db->from('userlog')->get()->result_array();
}

那么你的get这样写就可以了

// querycache arguments
print_r( $this->querycache->get( 'userlog', 'all', 7, 3 ) );

有更多参数就在get中加,参数从三个起顺序与模型相应的方法顺序一致即可

关于插入与更新时即调用execute方法

// insert or update
$insert_data = array(
 'recordtime' => time(),
 'action' => 'do something',
 'userid' => 5,
);
$this->querycache->execute( 'userlog', 'insert', array( $insert_data ) );

第三个参数必需是数组(用array包起来),如果有多个参数则array( $arg1, $arg2 ),顺序与模型对应方法顺序一致

function insert( $arg1, $arg2 )
{
 print_r( func_get_args() );
}

好吧,希望这个能帮到你,good night~~