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

     前几天我讲到在SqlParser中完成SQL的解析,我已经讲了distinct,field,table,group,order等的简单实现,那么怎么实现where呢,没有where,这个SQL一直还是不能运行的。

     对于where,我们可以想一下,允许用户输入的参数如:

    $this->where('uid > 1'),$this->where(array('uid' => array('gt' , 1)))

    这几种形式,首先第一种,就是直接将这段SQL通过字符串传递过来,这种在where函数中只需要拼接一个WHERE子串即可。

     对于传递的参数是数组的情况就比较复杂了,首先,对于最外层的array,它的形式应该是如下的:

     array(条件,条件,条件....)

     对于具体的某一个条件,它也是一个数组,如:

     字段=> array(比较符,数值,连接符)

     对于最简单的形式,如$this->where(array('uid' => array('gt',1)))它实际上被解析之后的SQL为:WHERE uid > 1,如果条件为多个:

     $this->where(array('uid' => array('gt' , 1)),'password' => array('neq' , 'test')),它代表的意思是:WHERE uid > 1 AND password != 'test',我们没有写条件与条件之间的连接符,应该框架自己会默认有一个连接符,如AND。

     由于对于符号:eq,neq,gt,gte等,我们需要将它解析成为如:=,!=,>,>=等,所以我们首先要定义一个函数来处理这个:

     我们称这个函数为:_parseCompExp,这个函数的实现为:

 

private function _parseCompExp($exp) {
		if(is_string($exp)) {
			return str_replace(array_keys($this->_compExp),array_values($this->_compExp),$exp);
		}elseif(is_array($exp)) {
			$tmpArr = array();
			foreach($exp as $val) {
				$tmpArr[] = str_replace(array_keys($this->_compExp),array_values($this->_compExp),$val);
			}
			return $tmpArr;
		} else {
			//不能解析,直接返回
			return $exp;
		}
	}


  为了扩展,我们不会将需要解析的参数写死,而是直接做成一个private的变量,如:


private $_compExp = array(
		'neq' => '!=',
		'gte' => '>=',
		'lte' => '<=',
		'notlike' => 'NOT LIKE',
		'gt' => '>',
		'lt' => '<',
		'eq' => '=',
		'like' => 'LIKE'
	);
   这个变量指定了每一个字符串代表的实际意义。


   具体的where的实现是怎么样的呢,我刚才写了一个实现,虽然看着很恶心:


private function _where($where) {
		if(empty($where)) {
			return '';
		}
		if(is_string($where)) {
			return ' WHERE ' . $where;
		}elseif(is_array($where)) {
			$str = ' WHERE ';
			$arrLen = count($where);
			$count = 0;
			foreach($where as $key => $val) {
				$needJoinStr = true;
				$joinStr = ' AND ';
				if(preg_match('/^lt|lte|gt|gte|eq|neq|like|notlike$/i',$val[0])) {
					$command = $this->_parseCompExp($val[0]);
					$str .= (' ' . $key . ' ' . $command . ' ' . $val[1]);
				} elseif('in' === strtolower($val[0])) {
					if(is_array($val[1])) {
						$str .= (' ( ' . $key . ' IN ' . implode(',',$val[1]) . ')');
					} else {
						$str .= (' ( ' . $key . ' IN ' . $val[1] . ' ) ');
					}
				} elseif('between' === strtolower($val[0])) {
					$data = explode(',',$val[1]);
					$str .= (' ' . $key . ' BETWEEN ' . $data[0] . ' AND ' . $data[1] . ' ');
				} else {}
				if($count + 1 < $arrLen) {
					if(isset($val[2])) {
						$str .= (' ' . $val[2] . ' ');
					} else {
						$str .= ' AND ';
					}
				}
				$count ++;
			}
			return $str;
		} else {}
	}
    由于这种比较符有这样几种:


    第一种:>,=,<等,这种后面跟的数值只有一个,如 > 1,这种的解析是比较简单的,只要通过parseCompExp函数转换一下,然后字符串拼接即可。

    第二种:IN,IN后面跟的参数个数不一定,所以需要判定后面传递的是数组还是字符串,如果是数组,那么需要通过,来explode成为字符串,如果是字符串,那就直接拼接即可。

    第三种,Between,后面跟的参数肯定是两个, 由于我为了简单,所以指定了第二个参数为数值,第三个参数为连接符,所以只有在第二个参数中设置数组来解决这个问题,如: 'uid' => array('between',array(2,4))它代表的意思就是:uid between 2 and 4。

    对于其他情况,暂不解析。

    再后面就是判定一下是否需要连接符,如果需要连接符,并且设置了数组的第三个元素,那么直接拼接,否则拼接AND。

    现在我们可以在模型中使用了,使用如下:

<?php
class TestModel extends ModelBase {
	public function test() {
		$this->distinct()->where()->field(array(
			'id' => 'uid','user'
		))->table(array(
			'user' => 'TEST','limits'
		))->group()->order(array(
			'test','test2' => 'asc'
		)) ->where(array(
			'id' => array('gt',1)
		))->select();
	}
}


   当然,这种实现是不完善的,反正先这样吧!!!

   本来一个完整的SQL不只是我们实现的这几个函数,为了简便,我就不讲后面复杂的内容了。

   对于其他框架实现的如:1对多,多对1这种多表查询,你们可以自己想一下怎么实现。

   后面我就粗略讲一下DbTable了,DbRelation我就不讲了,有兴趣去实现的童鞋可以自己试一下。



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