制作自己的MVC框架(二)——启动

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: app中就是控制器和视图,public中是入口文件和静态资源,library中既有框架的核心类,还有工具类,数据操作类等。

13.jpg


自己写了个框架,取名为“PrimusPHP”,就3个文件夹,log中是日志文件,会自动生成。

app中就是控制器和视图,public中是入口文件和静态资源,library中既有框架的核心类,还有工具类,数据操作类等。

这个框架会用到命名空间,PHP版本如果不能用命名空间,将不能执行。

 

一、单一入口


14.jpg


index.php”就是入口文件,“defined.php”设置一些通用常量,例如绝对目录,并且引入了初始化库。


define('ROOT', dirname(dirname(__FILE__)));
define('DS', DIRECTORY_SEPARATOR);
require_once LIB_PATH . DS . 'init.php';


index.php”就是在执行初始化方法。


require_once '../defined.php';
define('APP_NAME', 'weixin');
define('CONFIG_PATH', APP_PATH . DS . APP_NAME . DS . 'conf');
InitPrimus::getInstance();


二、初始化


private function __construct() {
        $this->environment();//环境配置
        $this->reporting();//错误报告
        self::loadFunction(self::$config['autoload']['helper']);//加载辅助函数
        $this->_autoload();//自动载入
        self::openLog(); //开启log
        self::loadClass('\library\core\Router');//路由
}


1)环境配置

通常会有三个配置环境,本地、测试和正式。

以前曾经把三个环境的参数写在一个文件中,然后版本控制的时候忽略文件,这样做很不方便。

尤其是在发布版本的时候,如果要变里面的参数,还得记得在哪里改。

现在直接分三个文件,各自管各自的,谁也影响不到谁。

library”中有三个配置文件,在“app”中也放在“conf”方便自行控制。


 如何判断当前环境是本地、测试还是正式环境呢?

这里我将这个变量埋在了“.htaccess”中,如果是nginx,也可以配置。


RewriteEngine on
SetEnv ENVIRONMENT local


2)错误报告

错误提示在调试的时候很有用,能定位到具体的行数,能提高修正效率。

在网上搜索了一下,找到了一些代码,再借鉴了CI的错误代码,嫁接到这个框架里。


set_error_handler('exception_error_handler');//追踪错误栈
register_shutdown_function('catch_fatal_error');//致命错误

exception_error_handler”和“catch_fatal_error”是两个函数,写在了“core/Common.php”中。


15.jpg


在“library/view”中预留了三种错误的模版页面。


16.jpg


在URL中输入“index/sign”错误的样子如下:


17.jpg


3)加载辅助函数

框架中,经常会有一些函数或类,在一开始就被载入进来,这里的这个辅助函数就是这个道理。

在配置文件中预先写好要载入的文件名。


public static function loadFunction($name) {
        if(is_array($name)) {
            foreach ($name as $key) {
                include_once HELPER_LIB_PATH .  DS . $key . '_helper.php';
            }
        }else {
            include_once HELPER_LIB_PATH .  DS . $name . '_helper.php';
        }
}


4)自动载入

当“new \library\xx()”某个类的时候,会自动进入到“spl_autoload_register”函数中。

在回调函数中将“\library\xx”修改为具体路径,在“include_once”进来,就初始化好了。


private function _autoload() {
        //$className是通过命名空间获取的
        spl_autoload_register(function ($className) {
            $dir = false;
            $classNames = explode('\\', $className);//分割为数组
            $autoDirs = self::$autoDirs;
            foreach ($autoDirs as $path) {
                $tmpInfo = pathinfo($path);
                if(in_array($tmpInfo['basename'], $classNames)) {
                    $dir = $tmpInfo['dirname'];
                    break;
                }
            }
            if($dir) {
                $file = $dir . DS . dir_replace_ds($className) . '.php';
                include_once($file);
            }
        });
}


5)日志

平时开发的时候,我喜欢将查询语句直接打印到日志中,当将代码放到线上了,也能调试各个语句的结果。

最近在做微信开发,有很多请求微信的服务器,这些请求的结果只能通过打印日志看到。

日志的类放在了“util/Log.php”中。


public function write($txt) {
        if(empty($txt) || !DEVELOPMENT_ENVIRONMENT) {
            return;
        }
        $name = date('Y-m-d') . '.log';
        if(!file_exists(LOG_PATH)) {
            mkdir(LOG_PATH, 0777, true);
        }
        $path = LOG_PATH . DS . $name;
        $content = date('Y-m-d H:i:s') . ' ' . $txt . "\n";
        file_put_contents($path, $content, FILE_APPEND);
}


三、路由


1)路由选择

路由支持两种,一种就是“index/index”,另外一种是“v1/index/index”。

第二种可以用于客户端接口,当客户端更新版本的时候,可能就需要新的接口,而老的接口又不能丢,就可以新开一个模块文件夹。

$params = explode('/', $uri);
        if(count($params) == 2) {
            $controller = $params[0];//控制器
            $action = $params[1];//操作方法
        }elseif(count($params) == 3) {
            $module = $params[0]; //模块
            $controller = $params[1];//控制器
            $action = $params[2];//操作方法
        }else {
            $controller = 'index';
            $action = 'index';
        }


2)路由重定向

以前没注意到重定向,最近在做微信开发的配置文件的时候就发现这个功能。

访问“bridge.js”其实是访问了某个控制器的“action”,怪不得我在想那些微信token都是通过服务器获取的,这个js文件是怎么搞到的。

18.jpg

重定向规则可以用正则表达式。

$init_conf['rewrite'] = array(
    '/new_bridge.js/' => 'index/config',
    '/new_bridge2.js/' => 'index/config2',
    '/p\/(\d+)/' => 'index/ticket?p=$1'
);


下面是正则匹配:

public function rewrite() {
        $config = \InitPrimus::getConfig('rewrite');
        foreach ($config as $src => $redirect) {
            //$pattern = '@^\/?' . $src . '\/?$@';
            if (\preg_match($src, $this->uri)) {
                $this->uri = \preg_replace($src, $redirect, $this->uri);
                break;
            }
        }
}



相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
6月前
|
前端开发 Java 程序员
从零基础手写Spring MVC框架,准备好进阶程序员了吗?
我们程序员大部分人都是野路子,不懂什么叫代码规范。写了一个月的代码,最后还得其他老司机花3天时间重构,相信大部分老司机都很头疼看新手的代码。
50 1
|
6月前
|
存储 前端开发 Java
Spring基础篇:MVC框架整合
Spring基础篇:MVC框架整合
|
6月前
|
设计模式 前端开发 JavaScript
浅谈MVC、MVP、MVVM框架模式
浅谈MVC、MVP、MVVM框架模式
63 0
|
6月前
|
前端开发 数据库 Python
Python Web 开发: 解释 Django 框架的 MVC 架构是什么?
Python Web 开发: 解释 Django 框架的 MVC 架构是什么?
126 0
|
6月前
|
Java 数据库连接 Maven
SSM框架整合:掌握Spring+Spring MVC+MyBatis的完美结合!
SSM框架整合:掌握Spring+Spring MVC+MyBatis的完美结合!
|
1月前
|
前端开发 Java
【案例+源码】详解MVC框架模式及其应用
【案例+源码】详解MVC框架模式及其应用
58 0
|
3月前
|
设计模式 存储 前端开发
MVC 框架的主要问题是什么?
【8月更文挑战第30天】
69 0
|
5月前
|
安全 前端开发 测试技术
安全开发-PHP应用&模版引用&Smarty渲染&MVC模型&数据联动&RCE安全&TP框架&路由访问&对象操作&内置过滤绕过&核心漏洞
安全开发-PHP应用&模版引用&Smarty渲染&MVC模型&数据联动&RCE安全&TP框架&路由访问&对象操作&内置过滤绕过&核心漏洞
|
6月前
|
前端开发 Java Spring
Java Web ——MVC基础框架讲解及代码演示(下)
Java Web ——MVC基础框架讲解及代码演示
65 1
|
6月前
|
前端开发 Java 应用服务中间件
Spring MVC框架概述
Spring MVC 是一个基于Java的轻量级Web框架,采用MVC设计模型实现请求驱动的松耦合应用开发。框架包括DispatcherServlet、HandlerMapping、Handler、HandlerAdapter、ViewResolver核心组件。DispatcherServlet协调这些组件处理HTTP请求和响应,Controller处理业务逻辑,Model封装数据,View负责渲染。通过注解@Controller、@RequestMapping等简化开发,支持RESTful请求。Spring MVC具有清晰的角色分配、Spring框架集成、多种视图技术支持以及异常处理等优点。
83 1