怎么一步步编写简单的PHP的Framework(十九)

        上一次我说了一下怎么从ModelBase通过Sql parse将SQL拆分,也就是解析的过程,今天我详细的说一下。

        首先,我们实现函数的链式操作,即如:$this->where()->table()->select()

         我们知道,如果要实现这种函数链,需要return $this,所以我们要保证在调用select方法之前的所有函数都要返回$this,也就是这个对象,最简单的方法就是在每个方法的最后执行return $this,但是这样实在是一个麻烦的事情,我们都知道PHP有一系列的魔术方法可以实现非常强大的功能,今天我们就要用到其中的一个魔术方法:__call,这儿方法是调用了对象中一个不存在的方法时调用的,也就是系统在抛出错误之前进行最后一次挽救,如果有__call,那么就将决定权交给__call,否则直接抛出错误。

        所以我们可以在ModelBase中定义一个__call方法,这个方法的内容如下:

 

	public function __call($method,$args) {
		if(in_array($method,array(
			'where','field','distinct','table','order','group'
		))) {
			$this->_options[$method] = isset($args[0]) ? $args[0] : null;
			return $this;
		} else {
			parent::__call($method,$args);
		}
	}


          由于我们在Base中也定义了__call,所以如果我们在这个类中的__call中无法处理的话,我们需要将控制权交给Base。

          由__call方法控制的方法是where,field,distinct,table,order,group,当然,这个不一定是全部的,我暂时就写这么几个,你们读了上次的文章应该知道这几个函数是处理什么内容了吧。

          这个__call方法执行的也很简单,就是在$this->_options数组里面将调用的方法的参数存储起来,这样用来做什么呢,这是为了后面Sql  parse调用的。

          我们把处理SQL的这个类称为SqlParser,那么SqlParser现在最少有以下几个方法:

         

  private function _where($where){}
  private function _field($field) {}
  private function _distinct($distinct) {}
  private function _table($table) {}
  private function _order($order) {}
  private function _group($group) {}

      可能你们会问为什么我要把这些方法设置为private呢,因为直接和ModelBase打交道的不是这些方法,假设我们把和ModelBase交互的这个方法称为execute,那么我们在ModelBase中只需要调用:

 

$this->_sqlParser->execute($this->_options);

   

      这个调用过程应该在哪儿调用呢,应该在select函数执行的时候。

     

	public function select() {
		$this->_sqlParser->execute($this->_options);
		$this->_db->prepare($this->_sqlParser->getSql());
		$this->_db->execute($this->_sqlParser->getParams());
	}

        这个就是ModelBase的select方法的代码,它实际上调用了sqlParser的实例的execute方法,然后在通过SqlParser的getSql和getParams方法获取SQL和参数分别交给驱动类的prepare和execute执行。

       那么现在ModelBase的代码就变成如下了:

<?php
class ModelBase extends Base {
	protected $_db = null;
	private $_sqlParser = null;
	private $_options = array(
		'where' => '',
		'field' => '',
		'distinct' => '',
		'table' => '',
		'order' => '',
		'group' => ''
	);
	public function __construct() {
		$this->_db = ConnectionManager::getConnection();
		$this->_sqlParser = new SqlParser();
	}
	public function execute($sql,Array $arr) {
		$this->_db->prepare($sql);
		$this->_db->execute($arr);
	}
	public function getAll() {
		return $this->_db->getAllByAssocArray();
	}
	public function __call($method,$args) {
		if(in_array($method,array(
			'where','field','distinct','table','order','group'
		))) {
			$this->_options[$method] = isset($args[0]) ? $args[0] : null;
			return $this;
		} else {
			parent::__call($method,$args);
		}
	}
	public function select() {
		$this->_sqlParser->execute($this->_options);
		$this->_db->prepare($this->_sqlParser->getSql());
		$this->_db->execute($this->_sqlParser->getParams());
	}
}
        那么SqlParser的代码是怎么样的呢,是这样的:

<?php
class SqlParser extends Base {
	private static $_templateSql = 'SELECT :distinct :field FROM :table WHERE :where :order :group';
	private $_sql = '';
	private $_params = array();
	public function execute(Array $options) {
		$this->_sql = str_replace(array(
			':distinct',':field',':table',':where',':group',':order'
		),array(
			$this->_distinct($options['distinct']),
			$this->_field($options['field']),
			$this->_table($options['table']),
			$this->_where($options['where']),
			$this->_group($options['group']),
			$this->_order($options['order'])
		),self::$_templateSql);
	}
	public function getSql() {
		return $this->_sql;
	}
	public function getParams() {
		return $this->_params;
	}
	
	private function _distinct($distinct) {
		return 'distinct';
	}
	private function _field($field) {
		return 'field';
	}
	private function _table($table) {
		return 'table';
	}
	private function _where($where) {
		return 'where';
	}
	private function _group($group) {
		return 'group';
	}
	private function _order($order) {
		return 'order';
	}

}
     在execute方法中,只需要按照SQL的模板(在变量templateSql中定义的)替换就行,比如对于templateSql中的:distinct(这个变量是用来占位的),当调用了$this->_distinct之后就会将templateSql中的:distinct替换成为相应的字符串。

      现在为了方便查看,对这几个比较重要的方法,我们都返回了一个字符串,这种后面SQL执行的时候肯定会报错,由于暂时我们没有写这些函数的具体实现,所以暂时就这样吧。

      好了,也差不多就这样吧,下次再继续了!!

你可能感兴趣的:(PHP,学习,framework,明庭令,Toper)