PHP框架意识

前言:

        其实语言并不重要,关键是开发思想,递增式的学习,会更加有收获;下面我将从分析一个电商项目进行整理一下自己所学的知识点,学会欣赏别人的代码!!!

1.框架意识

2.MVC设计思想

3.电商项目的分析

1.框架意识:

        其实我们一直都在接触框架,框架不是一件什么神奇的东西,首先:

  • 如果没有Apache这个服务器作为我们的底层框架,我们PHP的发送到服务器端的代码远远不止这么少。

  •  我们习以为常的_GET[]、_SESSION[]这些机制,其实也是封装好的东西,php预处理也是一种框架,只是不用我们去理会。

        下面介绍的这个项目,在PHP 层已经做得很好了,只是在VIEW层没有怎么处理(因为VIEW层现在技术可以达到模板语言,而不是传标签,解决IF语句,类似于node.js)

2.MVC设计思想:

本次分析的电商项目特点:

    抽象,单入口

    index:php?p=xxx&c=xxx & a=xxx;

与我之前架构的:

    直接,多入口:(多个功能多个文件)

2.1单入口的分析:

相比于之前的架构方式:将PHP文件下的模块功能分开

Notes:

        现在流行的Restful规范(TP5等)并不是简单的但入口而是对URL进行了语义化,路径分析(路由)

3.电商项目的分析:

Notes:

        由于该项目的路径地址是是根目录因此文件夹需要均放在外面

3.1.index.php:

//项目调试开关

define('APP_DEBUG',true);

//引入框架基础类

require './framework/Framework.class.php';

//运行项目

Framework::run();

项目调试开关,true的时候是我们会将错误信息打印出来,在正常给用户运行的时候,这里是关掉的。 

framework.class.php里的方法

private static function init(){

        //开启调试时,显示错误报告

        if(APP_DEBUG){

            ini_set('display_errors',1);

            error_reporting(E_ALL);

        }else{

            ini_set('display_errors',0);

            error_reporting(0);

        }

3.2.framework.class.php

//启动项目

  

 public static function run(){

        self::init(); //初始化

        self::registerAutoLoad(); //注册自动加载

        self::extend();   //扩展功能

        self::dispatch(); //请求分发

    }

类的静态方法和静态属性可以不用实例化对象直接使用(使用的方式是 类名::静态方法名 )

静态方法在读到这个类或者引入这个类文件的时候,就已经实例化并存放到内存中了,非静态类则需要new一下。

静态类在内存中即使有多个实例,静态的属性也只有一份。

::”这个叫范围解析操作符,又名域运算符   ‘- >’符号是“插入式解引用操作符”  用于类中,访问类里的函数或对象,比如:

<?php class Test { function do_test() { echo "Doing foo."; } } $bar = new Test; $bar->do_test(); ?>

PHP中=>和->以及::的用法实例可以参照这一篇文章

http://www.php.cn/php-weizijiaocheng-378631.html

 

3.2.1 路径配置:

//设置常量供项目内使用

    

        define('DS', DIRECTORY_SEPARATOR); //路径分隔符

        define('ROOT', getcwd().DS); //项目根目录

        define('APP_PATH', ROOT.'app'.DS); //应用目录

        define('FRAMEWORK_PATH', ROOT.'framework'.DS); //框架目录

        define('LIBRARY_PATH', FRAMEWORK_PATH.'library'.DS);//类库目录

        define('PUBLIC_PATH', ROOT.'public'.DS); //公开目录

        define('COMMON_PATH', APP_PATH.'common'.DS); //公共目录

DIRECTORY_SEPARATOR 这个是PHP预处理的变量,相当于输出路径分隔符,为什么要这样操作呢?

因为在LINUX上,路径是‘/’

而实际上多多数的网站我们会将他们配置到LINUX服务器上,所以这一点非常重要

3.3.3 注册自动加载:

//注册自动加载

 

private static function registerAutoLoad(){

        spl_autoload_register(function($class_name){

            $class_name = ucwords($class_name); //自动转换类名首字母大写

            if(strpos($class_name, 'Controller')){

                $target = CONTROLLER_PATH."$class_name.class.php";

                if(is_file($target)){

                    require $target;

                }else{

                    E('您的访问参数有误!');

                }

            }elseif(strpos($class_name, 'Model')){

                require MODEL_PATH."$class_name.class.php";

            }else{

                require LIBRARY_PATH."$class_name.class.php";

            }

        });

    }
spl_autoload_register(function($class_name)

如不是有这个方法的帮助下,PHP 的面向对象将会变得法场头疼,自动加载注册类,

E 函数:

//遇到致命错误,输出错误信息并停止运行

function E($msg){

    header('content-type:text/html;charset=utf-8');

    die('<pre>'.htmlspecialchars($msg).'</pre>');

}

3.3.4 获取请求参数:

//获取请求参数

    private static function getParams(){

        //获取URL参数

        $p = I('p','get','string','home');

        $c = I('c','get','string','index');

        $a = I('a','get','string','index');

        //获取pathinfo

        $pathinfo = self::getPathinfo();

        //定义常量表示 URL Rewrite 开关

        define('URL_REWRITE', (bool)$pathinfo);

        //开启URL Rewrite时,从pathinfo获取参数

        if(URL_REWRITE){

            $params = self::getPathinfoParams($pathinfo);

            //进行路由规则匹配

            $start = 0; //取出参数的起始下标

            if(isset($params[0]) && ($roule=C('URL_MAP_RULES')) && isset($roule[$params[0]])){

                list($p,$c,$a) = explode('/', $roule[$params[0]]);

                $start = (count($params)%2 > 0) ? 1 : 0; //根据参数个数,自动取出后面的参数

            }

            //将pathinfo参数保存到$_GET中

            for($len=count($params);$start<$len;$start+=2){

                if(isset($params[$start])){

                    $_GET[$params[$start]] = isset($params[$start+1]) ? $params[$start+1] : '';

                }

            }

        }

        //正则验证参数,要求以字母开头,后面跟0~20个 字母/数字/下划线 字符

        foreach(array($p,$c,$a) as $v) {

            preg_match('/^[A-Za-z]\w{0,20}$/',$v) || E('请求参数包含特殊字符!');

        }

        return array($p,$c,$a);

    }

最关键是弄懂这个I方法:

//接收变量

//变量名,方法,数据类型,默认值

function I($var,$method='post',$type='text',$def=''){

    switch($method){

        case 'get':    $method = &$_GET;    break;

        case 'post':   $method = &$_POST;   break;

        case 'cookie': $method = &$_COOKIE; break;

        case 'server': $method = &$_SERVER; break;

    }

    $value = isset($method[$var]) ? $method[$var] : $def;

    switch($type){

        //字符串类型

        case 'string': //字符串 不进行过滤

            $value = is_string($value) ? $value : '';

        break;

        case 'text': //字符串 进行HTML转义

            $value = is_string($value) ? trim(htmlspecialchars($value)) : '';

        break;

        case 'int': //整数

            $value = (int)$value;

        break;

        case 'id': //无符号整数

            $value = max((int)$value,0);

        break;

        case 'float': //浮点数

            $value = (float)$value;

        break;

        case 'bool': //布尔型

            $value = (bool)$value;

        break;

        case 'array': //数组型

            $value = is_array($value) ? $value : array();

        break;

    }

    return $value;

}

举个栗子,如果I(' ','get','string','index');

那么我们将会直接进入主页面,但是同时也不会将路径暴露给用户

//从pathinfo中获取参数,进行路由匹配

   

 private static function getPathinfoParams($pathinfo){

        //过滤URL后缀

        $suffix = C('URL_SUFFIX');

        $len = strlen($suffix);

        if(substr($pathinfo,-$len)==$suffix){

            $pathinfo = substr($pathinfo, 0, strlen($pathinfo)-$len);

        }

        //将pathinfo转换为数组

        return explode('/', trim($pathinfo, '/'));

    }

Notes:

$len = strlen($suffix);

        if(substr($pathinfo,-$len)==$suffix){

            $pathinfo = substr($pathinfo, 0, strlen($pathinfo)-$len);

        }

substr($pathinfo,-$len)==$suffix

//配置文件操作

function C($name,$value=null){

    static $config = null; //保存项目中的设置

    //函数首次被调用时载入配置文件

    if(!$config){

        $config = require COMMON_PATH.'config.php';

    }

    //省略value参数表示获取配置项,否则修改配置项

    if(is_null($value)){

        return isset($config[$name]) ? $config[$name] : '';

    }else{

        $config[$name] = $value;

    }

}

 

3.3.5  难点却很实用的会话存储:

SESSION_DB

//扩展功能

    private static function extend(){

        //配置时区

        date_default_timezone_set(C('DEFAULT_TIMEZONE'));

        //设置HttpOnly

        C('PHPSESSID_HTTPONLY') && ini_set('session.cookie_httponly', 1);

        //Session入库

        C('SESSION_DB') && new SessionDB();

        //配置 mbstring 扩展内置字符集

        mb_internal_encoding('UTF-8');

    }



<?php

//Session数据库转储

class SessionDB {

/*

    -- 数据库方式Session驱动

    create table `prefix_session` (

        `id` varchar(255) not null unique key,

        `expire` int(11) not null,

        `data` blob

    );

*/

    protected $lifeTime = '';

    protected $table = '';

    protected $db = null;

    public function __construct(){

        session_set_save_handler(

            array(&$this, 'open'),

            array(&$this, 'close'),

            array(&$this, 'read'),

            array(&$this, 'write'),

            array(&$this, 'destroy'),

            array(&$this, 'gc')

        );

    }

    public function open($savePath, $sessName) {

        $this->lifeTime = C('SESSION_EXPIRE') ? C('SESSION_EXPIRE') : ini_get('session.gc_maxlifetime');

        $this->table = C('DB_PREFIX') . 'session';

        $this->db = M();

        return true;

    }

    public function close() {

        $this->gc($this->lifeTime);

        return true;

    }

    public function read($sessID) {

        $sql = "select `data` from `$this->table` where `id`= :id and `expire` > :expire";

        $data = array('id' => $sessID,'expire' => time());

        $rst = $this->db->data($data)->fetchRow($sql);

        return isset($rst['data']) ? $rst['data'] : '';

    }

    public function write($sessID, $sessData) {

        $sql = "replace into `$this->table` (`id`,`expire`,`data`) values (:id, :expire, :data)";

        $data = array('id'=>$sessID,'expire'=>time() + $this->lifeTime,'data'=>$sessData);

        $this->db->data($data)->query($sql);

        return true;

    }

    public function destroy($sessID) {

        $sql = "delete from `$this->table` where `id`=:id";

        $data = array('id'=>$sessID);

        $this->db->data($data)->query($sql);

        return true;

    }

    public function gc($sessMaxLifeTime) {

        $sql = "delete from `$this->table` where `expire` < :expire";

        $data = array('expire'=>time());

        $this->db->data($data)->query($sql);

        return true;

    }

}

Session 数据木库转存需要按照PHP接口规范

Notes:

        php会话存储默认在服务器内存中,但是一旦服务器关闭就消失:

应用场景有:

        1.自动登录功能

        2.电商项目的购物车:本次案例重点讲解的是电商的购物车信息存储的问题

猜你喜欢

转载自blog.csdn.net/qq_37457202/article/details/84640755