个人开发心得(PHP,JS,SQL)

做PHP开发也四五年了,期间遇到无数的坑,填坑的过程中能力也得到了提升。现在通过文章的形式把PHP,JS,SQL中一些有趣的用法记录下来,希望对刚刚入门的同学有所帮助,还望老鸟手下留情,勿喷,哈哈。如果写的有错误,还望指正。
不定期更新
1.PHP中switch的另类用法
比如下面if elseif 的判断,当判断条件太复杂的时候,感觉会比较乱(PS:个人觉得)

 if($a == 1){

 }elseif ($b == 2) {
    # code...
 }elseif($c == 3){

 }elseif ($d == 4) {
    # code...
 }else{
    
 }

那么通过switch也能实现if elseif相同的功能,一般印象中,switch语句只能判别指定变量的不同的值,貌似JAVA的switch语句只能判断指定变量的值。

switch(true){
    case $a == 1:
        #code
        break;
    case $b == 2:
        #code
        break;
    case $c == 3:
        #code
        break;
    case $d == 4:
        #code
        break;
    default:
        #code 
        break;
}

结语:记得js也能使用这种结构,可能弱类型的语言的原因吧
2.MySQL where field in ()的另类写法
一般我们写where field in都是类似于这样:

select * from table where id in (1,2,3)

不过实际情况中,会有一张表中的多个类似的字段设定的值一样。
一般我们的写法可能会这样

select * from table where a = 1 or b = 1 or c = 1

那我们可以用where in来实现相同的目的

select * from table where 1 in (a,b,c)

PS:这类用法可能应用场景不大。哈哈
3.PHP foreach循环语句中使用引用,简化对数组单元的操作,比方赋值操作,更改原单元指定键值的值
先列一下一般的操作方法

foreach($array as $key => $row){
    $array[$key]['a'] = 1;
    $array[$key]['b'] = 2;
}

通过使用引用操作符&,我们可以这样操作

foreach($array as &$row){
    $row['a'] = 1;
    $row['b'] = 2;
}

PS:算偷点懒吧,哈哈
4.Thinkphp3.2.3使用中的一个坑
thinkphp在国内的粉丝还是很多的,框架也很成熟,不过用的过程中会有碰到一些比较尴尬的bug,今天开发中就遇到了这样的一个坑.使用模型里自动验证+自动完成组合使用时碰到的一个小bug,自动验证+自动完成都使用动态绑定操作.代码如下:

$validate = array(
                array("mobile","require","手机号必填"),
                array("mobile","/^1[34578]\d{9}$/","手机号码格式错误",1,"regex",3),
                array("mobile","","该手机号已存在",1,"unique",1),
                array("pwd","require","密码不能为空"),
                array("pwd","6,100","密码长度不能少于6位",1,"length",1),
            );
$auto = array(
                array("pwd","md5",1,"function"),
                array("name","小明",1),
                array("create_time",I("server.REQUEST_TIME"),1),
            );
if(!M("User")->validate($validate)->auto($auto)->create()){
    #code
}

因为在validate中有个检验手机号是否唯一的条件,unique这步验证会到用到Model类里的find操作,find操作后会清空Model中的属性options,这样就会导致模型的自动完成失效;
PS:所以有Model验证操作中有用unique操作的,不要将自动验证+自动完成合在一起操作,这样会导致自动完成失效.不过在模型中定义了$_validate和$_auto属性的不存在这个问题.

5.ThinkPHP3.2.3版本,凭自己的经验封装一个分页取数据的方法,其实就是为了偷个懒,少写点代码.
首先,先探究下Think\Model类中的select和count操作
select操作:

/**
     * 查询数据集
     * 
     * @access public
     * @param array $options 表达式参数
     * @return mixed
     */
    public function select($options=array()) {
        $pk   =  $this->getPk();
        if(is_string($options) || is_numeric($options)) {
            // 根据主键查询
            if(strpos($options,',')) {
                $where[$pk]     =  array('IN',$options);
            }else{
                $where[$pk]     =  $options;
            }
            $options            =  array();
            $options['where']   =  $where;
        }elseif (is_array($options) && (count($options) > 0) && is_array($pk)) {
            // 根据复合主键查询
            $count = 0;
            foreach (array_keys($options) as $key) {
                if (is_int($key)) $count++; 
            } 
            if ($count == count($pk)) {
                $i = 0;
                foreach ($pk as $field) {
                    $where[$field] = $options[$i];
                    unset($options[$i++]);
                }
                $options['where']  =  $where;
            } else {
                return false;
            }
        } elseif(false === $options){ // 用于子查询 不查询只返回SQL
            return  $this->buildSql();
        }
        // 分析表达式
        $options    =  $this->_parseOptions($options);
        // 判断查询缓存
        if(isset($options['cache'])){
            $cache  =   $options['cache'];
            $key    =   is_string($cache['key'])?$cache['key']:md5(serialize($options));
            $data   =   S($key,'',$cache);
            if(false !== $data){
                return $data;
            }
        }
        $resultSet  = $this->db->select($options);
        if(false === $resultSet) {
            return false;
        }
        if(empty($resultSet)) { // 查询结果为空
            return null;
        }

        if(is_string($resultSet)){
            return $resultSet;
        }

        $resultSet  =   array_map(array($this,'_read_data'),$resultSet);
        $this->_after_select($resultSet,$options);
        if(isset($options['index'])){ // 对数据集进行索引
            $index  =   explode(',',$options['index']);
            foreach ($resultSet as $result){
                $_key   =  $result[$index[0]];
                if(isset($index[1]) && isset($result[$index[1]])){
                    $cols[$_key] =  $result[$index[1]];
                }else{
                    $cols[$_key] =  $result;
                }
            }
            $resultSet  =   $cols;
        }
        if(isset($cache)){
            S($key,$resultSet,$cache);
        }
        return $resultSet;
    }

count操作:

/**
     * 利用__call方法实现一些特殊的Model方法
     * 
     * @access public
     * @param string $method 方法名称
     * @param array $args 调用参数
     * @return mixed
     */
    public function __call($method,$args) {
        if(in_array(strtolower($method),$this->methods,true)) {
            // 连贯操作的实现
            $this->options[strtolower($method)] =   $args[0];
            return $this;
        }elseif(in_array(strtolower($method),array('count','sum','min','max','avg'),true)){
            // 统计查询的实现
            $field =  isset($args[0])?$args[0]:'*';
            return $this->getField(strtoupper($method).'('.$field.') AS tp_'.$method);
        }elseif(strtolower(substr($method,0,5))=='getby') {
            // 根据某个字段获取记录
            $field   =   parse_name(substr($method,5));
            $where[$field] =  $args[0];
            return $this->where($where)->find();
        }elseif(strtolower(substr($method,0,10))=='getfieldby') {
            // 根据某个字段获取记录的某个值
            $name   =   parse_name(substr($method,10));
            $where[$name] =$args[0];
            return $this->where($where)->getField($args[1]);
        }elseif(isset($this->_scope[$method])){// 命名范围的单独调用支持
            return $this->scope($method,$args[0]);
        }else{
            E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
            return;
        }
    }

发现count操作实际是调用类的方法getField

/**
     * 获取一条记录的某个字段值
     * 
     * @access public
     * @param string $field  字段名
     * @param string $spea  字段数据间隔符号 NULL返回数组
     * @return mixed
     */
    public function getField($field,$sepa=null) {
        $options['field']       =   $field;
        $options                =   $this->_parseOptions($options);
        // 判断查询缓存
        if(isset($options['cache'])){
            $cache  =   $options['cache'];
            $key    =   is_string($cache['key'])?$cache['key']:md5($sepa.serialize($options));
            $data   =   S($key,'',$cache);
            if(false !== $data){
                return $data;
            }
        }        
        $field                  =   trim($field);
        if(strpos($field,',') && false !== $sepa) { // 多字段
            if(!isset($options['limit'])){
                $options['limit']   =   is_numeric($sepa)?$sepa:'';
            }
            $resultSet          =   $this->db->select($options);
            if(!empty($resultSet)) {
                $_field         =   explode(',', $field);
                $field          =   array_keys($resultSet[0]);
                $key1           =   array_shift($field);
                $key2           =   array_shift($field);
                $cols           =   array();
                $count          =   count($_field);
                foreach ($resultSet as $result){
                    $name   =  $result[$key1];
                    if(2==$count) {
                        $cols[$name]   =  $result[$key2];
                    }else{
                        $cols[$name]   =  is_string($sepa)?implode($sepa,array_slice($result,1)):$result;
                    }
                }
                if(isset($cache)){
                    S($key,$cols,$cache);
                }
                return $cols;
            }
        }else{   // 查找一条记录
            // 返回数据个数
            if(true !== $sepa) {// 当sepa指定为true的时候 返回所有数据
                $options['limit']   =   is_numeric($sepa)?$sepa:1;
            }
            $result = $this->db->select($options);
            if(!empty($result)) {
                if(true !== $sepa && 1==$options['limit']) {
                    $data   =   reset($result[0]);
                    if(isset($cache)){
                        S($key,$data,$cache);
                    }            
                    return $data;
                }
                foreach ($result as $val){
                    $array[]    =   $val[$field];
                }
                if(isset($cache)){
                    S($key,$array,$cache);
                }                
                return $array;
            }
        }
        return null;
    }

通过分析代码我们发现,select操作和count操作最后都是通过$this->db->select($options)这段代码从数据库里获取数据的.而这个$options局部变量都是通过$this->_parseOptions($options);这个方法赋值的.
发现了这个共同点,那么我们就开始封装一个分页取数据,返回总条数和指定的分页数据:
(1)定义一个BaseModel类继承自Think\Model的基类

namespace Common\Model;
use Think\Model;
class BaseModel extends Model{

}

(2)实现分页取数据的方法

namespace Common\Model;
use Think\Model;
class BaseModel extends Model{
        /**
     *
     * 默认获取数据表10条记录每次
     * @param $print_return
     * 默认分页取数据 @param $needLimit
     * @return array
     */
    public function getList($needLimit = true,$print_return = false){
        $options = $this->options;
        $options['alias'] = isset($this->options['alias']) ? $this->options['alias'] : 'a';
        if(isset($this->options['order']) && !empty($this->options['order'])){
            $options['order'] = $this->options['order'];
        }else{
            if(in_array('create_time',$this->fields)){
                $options['order'] = $options['alias'].".create_time desc";
            }
        }
        /*没限制分页,则默认每次取10条*/
        if($needLimit){
            if(empty($this->options['page']) && empty($this->options['limit'])){
                $pindex = max(1,intval(I('p',1)));
                $psize = C('PER_PAGE');
                $limit = intval($pindex-1)*$psize.','.$psize;
                $this->limit($limit);
                $options['limit'] = $this->options['limit'];
            }
        }
        $this->options = $options;
        //统计数据不需要ORDER
        unset($this->options['order']);
        $total = $this->count();
        $this->options = $options;
        $rows = $this->select();
        $return = array(
            'total' => $total,
            'rows' => $rows,
            'list' => $rows,
            'status' => 1,
            'page' => max(1,intval(I('p',1))),
            //'sql' => APP_DEBUG ? $this->_sql() : '',
            'pages' => $total % C('PER_PAGE') == 0 ? $total / C('PER_PAGE') : ceil($total / C('PER_PAGE'))
        );
        //需要打印结果时
        if($print_return){
            var_dump($return);
        }
        return $return;
    }
}

(3):开始在控制器里使用这个封装好的类
不能直接使用D的助手函数直接实例化BaseModel,因为会找不到这个base这个表,所以如果用D方法就需要你操作的表的Model继承自BaseModel;
或者可以自行封装一个M方法差不多的助手函数,只不过实例化的时候是实例化BaseModel而不是Think\Model;
下面我用User这个来示例:

public function index(){
    $data = D("User")->field($field)->where($where)->join()->order("uid desc")->limit("1,10")->getList();
}

$data中包含满足条件的总数和对应分页的数据
PS:封装的时候默认给被操作的主表设置了一个别名(a)为了兼容join操作,所以取主表字段或者设置主表字段条件的时候需要在字段前加个a,从表的别名根据自己的实际情况来设.

6.Javascript简化Ajax提交数据的封装
比如,有时我们需要用Ajax提交的数据在一个表单中,而这个表单里有很多字段并且这些字段都需要提交到服务器,如果我们一个一个取组装这些数据,那么这个代码量就会很大,也有可能产生遗漏的问题.
既然问题已经提出来了,那么我们就来解决这个问题.
先了解下Jquery中封装的$.ajax(),$.get(),$.post()的方法介绍,提交数据的格式支持a=1&b=2&c=3和Object对象形式两种.
对象形式如下:

{
  a:1,
  b:2,
  c:3
}

使用简便方法前,需要给指定的form标签设置一个ID(例如:id="form"),第一种数据格式我们可以直接使用Jquery自带的方法serialize()方法得到;
代码如下:

var form = $("#form").serialize();

而第二种方法则需要自己封装一个方法,这个网上有很多,下面贴一个我自己平时常用的一段封装好的代码:

<script>
(function($){
    $.fn.serializeJSON = function()
    {
        var o = {};
        var a = this.serializeArray();
        $.each(a, function() {
            if (o[this.name] !== undefined) {
                if (!o[this.name].push) {
                    o[this.name] = [o[this.name]];
                }
                o[this.name].push(this.value || '');
            } else {
                o[this.name] = this.value || '';
            }
        });
        return o;
    };
})(jQuery);
</script>

上述代码一定要写在引入Jquery类库文件之后,否则会报错.
使用方法如下:

<script>
var form = $("#form").serializeJSON();
</script>

得到表单的数据为以表单元素name为建,value为值的数据.
应用到Ajax中:

<script type="text/javascript">
    var form = $("#form").serialize();
        //var form = $("#form").serializeJSON();
    $.ajax({
        url:"",
        dataType:"json",
        data:form,
        success:function(res){
            #code
        }
    });
    $.post("",form,function(res){
        #code
    });
    $.get("",form,function(res){
        #code
    });
</script>

这样就能简化封装ajax需要提交的数据

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容