第一阶段
定义核心类
定义单入口,创建所需要的文件夹。
在KUAIXUEPHP下创建index.php
里面载入单入口
<?php
require "./KUAIXUEAPP/KUAIXUEAPP.php";
?>
定义核心类KUAIXUEPHP.php
1.设置常量
2.创建目录
3.载入必须的文件
4.执行应用类
<?php
final class KUAIXUEPHP{
//核心run方法
public static function run(){
1.设置常量 self::_set_const(); //定义框架与用户的路径方便以后使用
2.创建目录 self::_create_dir(); //自动创建所需目录
3.载入必须的文件 self::_import_file(); //载入框架所需函数文件和类文件
4.执行应用类 Application::run();
}
private static function _set_const(){
//\WWW\KUAIXUEAPP\KUAIXUEAPP\KUAIXUEAPP.php
#var_dump(__FILE__);
$path = str_replace('\\','/',__FILE__);
define('KUAIXUEPHP_PATH',dirname($path));
define('CONFIG_PATH',KUAIXUEPHP_PATH. '/Config');
define('DATA_PATH',KUAIXUEPHP_PATH. '/Data');
define('TPL_PATH',DATA_PATH.'/Tpl');
define('LIB_PATH',KUAIXUEPHP_PATH. '/Lib');
define('CORE_PATH',LIB_PATH. '/Core');
define('FUNCTION_PATH',LIB_PATH. '/Function');
define('ROOT_PATH',dirname(KUAIXUEPHP_PATH));
//ROOT_PATH; D:/phpStudy/PHPTutorial/WWW/KUAIXUEAPP
//临时目录
define('TEMP_PATH',ROOT_PATH . '/Temp');
//日志目录
define('LOG_PATH',TEMP_PATH.'/Log');
define('APP_PATH',ROOT_PATH. '/'. APP_NAME);
define('APP_CONFIG_PATH',APP_PATH.'/Config');
define('APP_CONTROLLER_PATH',APP_PATH.'/Controller');
define('APP_TPL_PATH',APP_PATH.'/Tpl');
define('APP_PUBLIC_PATH',APP_TPL_PATH.'/Public');
define('KUAIXUEPHP_VERSION','1.0');
}
private static function _create_dir(){
//创建一个数组,数组是之前定义的目录路径
$arr = array(
APP_PATH,
APP_CONFIG_PATH,
APP_CONTROLLER_PATH,
APP_TPL_PATH,
APP_PUBLIC_PATH,
TEMP_PATH,
LOG_PATH
);
//循环数组,判断文件夹是否存在,如果不存在就创建文件夹
foreach ($arr as $v){
is_dir($v) || mkdir($v,0777,true);
}
private static function _import_file(){
$fileArr = array(
CORE_PATH . '/Log.class.php',
FUNCTION_PATH . '/function.php', //调用function函数
CORE_PATH . '/Controller.class.php',
CORE_PATH . '/Application.class.php'
);
foreach ($fileArr as $v){
require_once $v; //包含文件,require去调用函数文件和类文件
}
}
}
KUAIXUEPHP::run(); //入口处
?>
设置index.php和admin.php两个不同的模式,用户和管理员
admin.php
<?php
define('APP_NAME','Admin');
require "./KUAIXUEAPP/KUAIXUEAPP.php";
index.php
define('APP_NAME','Index');
require "./KUAIXUEAPP/KUAIXUEAPP.php";
APP_NAME分别对应不同的路径,当访问前台时会自动创建。
4.执行应用类
在/Lib/Core目录下创建Application.class.php
在Function目录下创建function.php
final class Application{//Application.class.php
public static function run(){
p(1);
}
}
<?php //function.php
function p($arr){
echo ' <pre>';
print_r($arr);
echo '</pre>';
通过加载文件来执行函数,利用框架的扩展性。
初始化框架准备之C函数
建立框架的Config.php,返回数组
<?php
return array(
'CODE_LEN' => 4,
'DEFAULT_TIME_ZONE' => 'PRC',
'SESSION_AUTO_START' => true,
'VAR_CONTROLLER' => 'c',
'VAR_ACTION' => 'a',
'SAVE_LOG' => true,
//错误跳转的地址
'ERROR_URL' =>'',
//错误提示的信息
'ERROR_MSG' => '网站出错了请稍后再试'
);
建立用户Config,自动建。
核心函数c函数
1.加载配置项Config
2.读取配置项
3.临时动态改变配置项
4.读取所有配置项。
function C($var = NULL , $value = NULL){
static $config = array();
//数组的形式进入
if (is_array($var)){
$config = array_merge($config,array_change_key_case($var,CASE_UPPER)
);
return; //不走下面
}
if (is_string($var)){
$var = strtoupper($var);
//传递两个参数
if(!is_null($value)){
$config[$var] = $value;
return;
}
return isset($config[$var])? $config[$var]:NULL;
}
if (is_null($var) && is_null($value)){
return $config;
}
}
初始化框架之加载配置项与时区
重新改写Application.class.php
final class Application{//Application.class.php
public static function run(){
self::_init(); //初始化框架加载配置项与时区
self::_set_url(); //设置外部路径
spl_autoload_register(array(__CLASS__,'_autoload')); //当有方法实例化时会自动调用 //自动载入
self::_create_demo(); //创建用户所需文件
self::_app_run(); //通过get参数实例化应用类
}
private static function _init(){
//加载配置项
C(include CONFIG_PATH . '/config.php');
$userPath = CONFIG_INDEX_PATH . '/config.php'; //创建用户所需config文件.
$userConfig = <<<str
<?php
return array(
//配置项 => 配置值
);
?>
str;
is_file($userPath) || file_put_contents($userPath, $userConfig); //判断用户是否有配置项,有就不覆盖,没有就创建。
//加载用户配置项
C(include $userPath);
//设置默认时区
date_default_timezone_set(C('DEFAULT_TIME_ZONE'));
//开启session
C('SESSSION_AUTO_START') && session_start();
}
private static function _set_url(){ //设置外部路径,用来当css,js的变量引用。
$path = 'http://' . $_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
$path = str_replace('\\','/',$path);
define('__APP__',$path);
define('__ROOT__',dirname(__APP__));
define('__TPL__',__ROOT__ . '/' . APP_NAME . '/Tpl');
define('__PUBLIC__',__TPL__.'/Public');
}
private static function _create_demo(){
$path = APP_CONTROLLER_PATH . '/IndexController.class.php';
$str = <<<str
<?php
class IndexController extends Controller{
public function index(){
header('Content-type:text/html;charset=utf-8');
echo '欢迎使用凌云框架(:';
}
}
str;
is_file($path) || file_put_contents($path,$str);
}
private static function _app_run(){
$c = isset($_GET[C('VAR_CONTROLLER')])? $_GET[C('VAR_CONTROLLER')] : 'Index';
$a = isset($_GET[C('VAR_ACTION')])? $_GET[C('VAR_ACTION')] : 'index';
$c .='Controller';
$obj = new $c();
$obj->$a();
}
}
day10 通过get参数来实现控制类
self::_app_run();
private static function _app_run(){
$c = isset($_GET[C('VAR_CONTROLLER')])? $_GET[C('VAR_CONTROLLER')] : 'Index';
$a = isset($_GET[C('VAR_ACTION')])? $_GET[C('VAR_ACTION')] : 'index';
$c .='Controller';
$obj = new $c();
$obj->$a();
}
相当于调用不同的控制器,比如说我传入参数c=Arc
事实上我们通过控制器来操作不同的类。思想很简单.
在config.php中添加变量c和a
day13增加初始化方法
在Controller类下
public function __construct()
{
echo '父类必须执行构造方法';
if (method_exists($this,'__auto')){
$this -> __auto();
}
if (method_exists($this,'__init')){
$this -> __init();
}
}
然后让IndexController.class.php下
public function __auto(){
echo '应用Index方法执行';
}
当子类对象被实例化执行时,先执行父类的__Construct方法。
day14日志函数的编写与理解
在Core文件夹下建立Log.class.php
<?php
/**
* Created by PhpStorm.
* User: jing
* Date: 2021-10-26
* Time: 20:38
*/
class Log{
//$msg错误日志信息,$level等级,$type文件保存3,$dest目标
static public function write($msg,$level='ERROR',$type=3,$dest=NULL){
if (!C('SAVE_LOG')) return; //如果没有开启不走下面
if (is_null($dest)){//路径为空的话,定义常量,在框架下建立临时目录/temp/log
$dest = LOG_PATH . '/' . date('Y_m_d'). ".log";
}
if (is_dir(LOG_PATH)) error_log("[TIME]:" .date('Y-m-d H:i:s')."{$level}:{msg}\r\n",$type,$dest);
}
}
?>
配置Config.php文件加入日志开启的参数
'SAVE_LOG' => true,
1.定义路径
临时目录存放
//临时目录
define('TEMP_PATH',ROOT_PATH . '/Temp');
//日志目录
define('LOG_PATH',TEMP_PATH.'/Log');
2.创建目录数组中添加他们
private static function _create_dir(){
$arr = array(
APP_PATH,
APP_CONFIG_PATH,
APP_CONTROLLER_PATH,
APP_TPL_PATH,
APP_PUBLIC_PATH,
TEMP_PATH,
LOG_PATH
);
3.error_log函数写入报错信息
如果在目录下存在log文件,那么写入日志报错信息\r\n。
4.最后载入类文件
private static function _import_file(){
$fileArr = array(
CORE_PATH . '/Log.class.php',
FUNCTION_PATH . '/function.php',
CORE_PATH . '/Controller.class.php',
CORE_PATH . '/Application.class.php'
);
day15更新debug功能,防止安全隐患
在index.php目录下定义debug功能(默认开启)
define('DEBUG',TRUE);
为了只想在debug时爆错信息出现在网站上,我们增加一个boot.php来临时保存我们的核心类文件比如说Application,Controller,以及Log。所以我们在载入文件方法下增加临时的boot文件
private static function _import_(){
//载入类文件和函数
$file_path = array(
_Core_. '/Log.class.php',
_Function_ . '/function.php',
_Core_ .'/Controller.class.php',
_Core_ .'/Application.class.php'
);
$str = ''; //定义str来存放我们核心代码
foreach($file_path as $v){
$str .= trim(substr(file_get_contents($v),5,-2)); //从第6个字母开始写入到$str
require_once $v;
}
$str = "<?php\r\n" .$str;
file_put_contents(TEMP_PATH.'/~boot.php',$str)||die('access not allow'); //写入boot临时文件,里面包含了我们所有的核心类
}
然后在KUAIXUEPHP.php目录下修改类KUAIXUEPHP
final class KUAIXUEPHP {
public static function run(){
self::_set_path();
defined('DEBUG') || define('DEBUG',false);
if(DEBUG){
self::_create_dir(); //开启debug正常执行
self::_import_();
}else{
error_reporting(0); //关闭错误报错到页面,防止安全隐患
require TEMP_PATH . '/~boot.php'; //如果关闭debug,直接载入临时类文件,不影响程序正常运行
}
Application::run();
}
当我们报错时关闭debug模式
没有报错信息出现在首页,防止hacker攻击
当我们开启debug时
报错会直接显现在首页,可以帮助使用者进行分析。
day16编写增强打印函数P函数和go跳转函数
重新更新p函数,防止true,null不能输出,在function.php下编写
打印函数
function p($arr){
if (is_bool($arr)){
var_dump($arr);
}else if (is_null($arr)){
var_dump(NULL);
}else{
echo '<pre'. print_r($arr,true).'</pre>';
}
}
跳转函数
function go($url,$time=0,$msg=''){ //跳转函数
if (!headers_sent()){
$time ==0 ? header('Location:'.$url):header("refresh: {$time};url={$url}");
die($msg);
}else{
echo "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
if (time) die($msg);
}
}
当使用跳转函数时一定要添加http://
day17halt函数与halt页面代码追踪
在function下添加
function halt($error,$level = 'ERROR',$type=3,$dest=NULL){
if(is_array($error)){
Log::write($error['message'],$level,$type,$dest);
}else{
Log::write($error,$level,$type,$dest);
}
$e = array();
if(DEBUG){
if (!is_array($error)){ //不是数组的情况
$trace = debug_backtrace();
$e['message'] = $error;
$e['file'] = $trace[0]['file'];
$e['line'] = $trace[0]['line'];
$e['class'] = isset($trace[0]['class']) ? $trace[0]['class'] : '';
$e['function'] = isset($trace[0]['function']) ? $trace[0]['function'] : '';
ob_start();
debug_print_backtrace();
$e['trace'] = htmlspecialchars(ob_get_clean());
}else{ //数组时的情况
$e = $error;
}
}else{
if($url = C('ERROR_URL')){
go($url);
}else{
$e['message'] = C('ERROR_MSG');
}
}
include DATA_PATH . '/Tpl/halt.html';
die;
}
并且导入halt.html
在config.php下添加两个变量
//错误跳转的地址
'ERROR_URL' =>'',
//错误提示的信息
'ERROR_MSG' => '网站出错了请稍后再试'
效果
有thinkphp那点味了。
day18编写display函数加载index目录并且增添assign功能
首先在Tpl下创建Index/index.php
在核心类Application.class.php下加入定义
define('CONTROLLER',$c);
define('ACTION',$a);
使用print_const函数实验效果,在function.php下编写函数
function print_const(){
$const = get_defined_constants(true);
p($const['user']);
}
使用函数
出现我们需要的变量
现在编写display方法
在核心类Controller类下建立方法
protected function display($tpl=NULL){
if (is_null($tpl)){
$path = APP_TPL_PATH . '/' . CONTROLLER . '/' . ACTION . '.html';
#echo $path;
}else{
$suffix = strrchr($tpl,'.');
$tpl = empty($suffix) ? $tpl . '.html' : $tpl;
$path = APP_TPL_PATH . '/' . CONTROLLER . '/' . $tpl;
}
if (!is_file($path)) halt($path . '模板文件不存在');
#p($this->ver);
var_dump($this->ver); // 'var' => string '草泥马' (length=9)
//肯定是要把indexController中的var加载到这里
//所以我们使用变量覆盖来覆盖$var
extract($this->ver); //变量覆盖后,相当于在display方法下定义$var = 你传入的任意数
echo $var;
#var_dump($this->ver);
include $path; //加载文件
}
运行display方法,两种情况,如果有index目录,我们直接运行出现结果,如果没有,会使用halt方法进行报错处理.
如果没有
但是发现我们定义的
v
a
r
在
i
n
d
e
x
C
o
n
t
r
o
l
l
e
r
下
确
实
无
法
跟
进
i
n
d
e
x
.
h
t
m
l
目
录
,
根
本
原
因
是
因
为
var在indexController下确实无法跟进index.html目录,根本原因是因为
var在indexController下确实无法跟进index.html目录,根本原因是因为var是局部变量,因为display方法下并没有定义$var变量,所以也就无法加载成功,例如
所以我们需要一个方法在运行时加载var变量到display方法下
编写assign方法,在核心类Controller.class.php下
protected function assign($var,$value){
$this->ver[$var] = $value;
}
然后在此文件(Controller)下增添一个数组用来接收$var
private $ver = array();
思想很明确,assign方法会接收,$var我们打下断点来看一下
这里我们可以看出来数组ver里面存储着var的值是CTFer,我们可以使用extract方法来让变量覆盖,因为我们无法直接操控ver数组里面的东西让他等于var,所以我们选择变量覆盖直接覆盖调var,然后就可以直接调用$var
例如
至此,我们的两个方法就编写完毕,可能变量覆盖哪里的确有点绕.
day19 定义IS_POST和IS_AXAJ变量
首先写一个表单来进行post登录
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src = "<?php echo __PUBLIC__ ?>/JS/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
$(function () {
$('form').submit(function () {
$.ajax({
url : '<?php echo __APP__ ?>',
})
})
})
</script>
</head>
<body>
<form action = "javascript:;" method="post" >
<input type="text" name="username" id="" />
<br />
<input type="password" name="password" id="" />
<br />
<input type="submit" value="提交" />
</form>
</body>
</html>
导入
然后在IndexController.class.php下打印$_SERVER
然后通过REQUEST_METHOD来判断post方法还是get方法
定义IS_POST
define('IS_POST',($_SERVER['REQUEST_METHOD']) == 'POST') ? true : false;
通过异步来判断是否为post传递
我们先看如果是普通的调用
并没有HTTP_X_REQUESTED_WITH这个变量在打印p($_SERVER);时
如果我们通过post点击,然后F12观看返回数据
出现HTTP_X_REQUESTED_WITH = XMLHttpRequest变量,那么我们就可以通过他来判断IS_AJAX变量
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
define('IS_AJAX',true);
echo IS_AJAX;
}else{
define('IS_AJAX',false);
echo IS_AJAX;
}
在KUAIXUEAPP.php下添加如上两个变量。
day20创建公共文件夹
在KUAIXUEAPP.php文件中添加以下定义,并添加到_create_dir方法下
//创建公共
define('COMMON_PATH', ROOT_PATH . '/Common');
//公共配置项文件夹
define('COMMON_CONFIG_PATH',COMMON_PATH . '/Config');
//公共模型文件夹
define('COMMON_MODEL_PATH',COMMON_PATH . '/Model');
//公共库文件夹
define('COMMON_LIB_PATH',COMMON_PATH . '/Lib');
//创建应用目录
private static function _create_dir(){
$arr = array(
COMMON_CONFIG_PATH,
COMMON_MODEL_PATH,
COMMON_LIB_PATH,
APP_PATH,
APP_CONFIG_PATH,
APP_CONTROLLER_PATH,
APP_TPL_PATH,
APP_PUBLIC_PATH,
TEMP_PATH,
LOG_PATH
);
day21公共配置项功能实现
private static function _init(){
C(include CONFIG_PATH . '/config.php'); //载入框架config
//载入公共文件config
$commonpath = COMMON_CONFIG_PATH . '/config.php';
$commonConfig = <<<str
<?php
return array(
//配置项 =>配置值
);
str;
is_file($commonpath) || file_put_contents($commonpath,$commonConfig);
C(include $commonpath);
$userPath = APP_CONFIG_PATH . '/config.php';
$userConfig = <<<str
<?php
return array(
//配置项 =>配置值
);
str;
is_file($userPath) || file_put_contents($userPath,$userConfig);
//加载用户配置项
C(include $userPath); //载入用户config
//设置默认时区
date_default_timezone_get(C('DEFAULT_TIME_ZONE'));
C('SESSION_AUTO_START')&& session_start();
}
增添公共配置项的创建
day22用户自定义扩展功能实现
创建如下文件夹
在核心类Application.class.php下编写载入公共文件夹函数
private static function _user_import(){
$fileArr = C('AUTO_LOAD_FILE');
if (is_array($fileArr) && !empty($fileArr)){
foreach ($fileArr as $v){
require_once COMMON_LIB_PATH . '/' . $v;
}
}
}
效果就是可以使用自定义函数
day23-24工具类实现自动载入
在KUAIXUEAPP.php下添加目录
define('EXTENDS_PATH',KUAIXUEPHP_PATH. '/Extends');
define('TOOL_PATH',EXTENDS_PATH. '/Tool');
define('ORG_PATH',EXTENDS_PATH. '/Org');
创建目录
Code类下
然后改写载入类的代码
private static function _autoload($className){
switch (true){
//判断是否为控制器controller控制器
case strlen($className) > 10 && substr($className, -10) == 'Controller';
$path = APP_CONTROLLER_PATH . '/' . $className . '.class.php';
if (!is_file($path)) halt($path . '控制器未找到');
include $path;
break;
default:
//判断是否为其他类
$path = TOOL_PATH .'/' . $className . '.class.php';
echo $path;
if(!is_file($path)) halt($path . '类未找到');
include $path;
break;
}
#echo $className;
}
然后在IndexController下引用
如果控制器不存在
如果类不存在
day25~26空控制器EmptyController
实现用户乱输入,跳转到空控制器
在类加载函数这里进行判断,如果存在则执行,不存在去判断empty是否存在,不存在就执行控制器未找到,存在就包含路径。
private static function _autoload($className){
switch (true){
//判断是否为控制器controller控制器
case strlen($className) > 10 && substr($className, -10) == 'Controller';
$path = APP_CONTROLLER_PATH . '/' . $className . '.class.php';
if (!is_file($path)){
$emptyPath = APP_CONTROLLER_PATH . '/EmptyController.class.php';
if (is_file($emptyPath)){
include $emptyPath;
return;
}else{
halt($path . '控制器未找到');
}
}
include $path;
break;
default:
//判断是否为其他类
$path = TOOL_PATH .'/' . $className . '.class.php';
echo $path;
if(!is_file($path)) halt($path . '类未找到');
include $path;
break;
}
#echo $className;
}
类没有找到
如果直接包含一个没有找到的类文件,一定会爆这个类不存在,
我们可以在这个类实例化前判断类是否存在
然后改写_app_run方法(作用:(通过get参数实例化应用类))判断$c这个类是否存在,存在执行不存在执行EmptyController方法
if (class_exists($c)){ //判断c输入的控制器类是否存在,存在就执行
$obj = new$c();
$obj->$a();
}else{ //不存在就执行空控制器
$obj = new EmptyController();
如果要是输入参数a,那么我们就需要判断两个,类存在,方法存在,所以继续改写
if (class_exists($c)){
$obj = new $c();
if (!method_exists($obj,$a)){
if (method_exists($obj, '__empty')){
$obj->__empty();
}else{
halt($c . '控制器中' . $a .'方法不存在');
}
}else{
$obj->$a();
}
}else{
$obj = new EmptyController();
$obj->index();
}
并且在indexController.class.php下增加方法
public function __empty(){
echo 'empty method';
}
当方法不存在时
当类不存在时
当方法和类都不存在时
解决了用户输入错误的提示,使框架更美观
day27-错误处理信息之set_error_handler函数
使用set_error_handler函数来处理错误信息。
我来介绍一下什么是set_error_handler方法
例子
<?php
//error handler function
function customError($errno, $errstr, $errfile, $errline) {
echo "<b>Custom error:</b> [$errno] $errstr<br />";
echo "Error on line $errline in $errfile<br />";
echo "Ending Script";
die();
}
//set error handler
set_error_handler("customError");
$test=2;
//trigger error
if ($test > 1) {
trigger_error("A custom error has been triggered");
}
?>
需要注意的是:
set_error_handler(“customError”) 不仅可以接受函数,还可以接受 类的方法(公开的静态方法 及 公开的非静态方法 都可以),但需要以 数组形式 传递,数组的第一值为“类名”,第二个参数为“方法名”,如下代码所示:
<?php
class App{
//error handler function
public static function customError($errno, $errstr, $errfile, $errline) {
echo "<b>Custom error:</b> [$errno] $errstr<br />";
echo "Error on line $errline in $errfile<br />";
echo "Ending Script";
die();
}
}
//set error handler
set_error_handler(array("App","customError"));
$test=2;
//trigger error
if ($test > 1) {
trigger_error("A custom error has been triggered");
}
?>
他的四个参数含义:
- $errno 错误编号
- $errstr 错误消息
- $errfile 错误所在的文件
- $errline 错误所在的行
我们来尝试写这个方法,首先在核心类application下
然后编写error方法
public static function error($errno , $error , $file, $line){
switch ($errno){
case E_STRICT:
case E_USER_WARNING:
case E_USER_NOTICE:
default:
if(DEBUG){
include DATA_PATH . '/Tpl/notice.html';
}
break;
}
}
notice.html
<style type="text/css">
div.hdphp_notice {
border : 1px solid #990000;
font-family: Monaco,Menlo,Consolas,"Courier New",monospace;
padding-left: 20px;
margin: 10px;
}
div.hdphp_notice h3{
font-size: 18px;
margin: 20px 0;
}
div.hdphp_notice p {
font-size: 14px;
margin: 15px 0;
}
</style>
<div class="hdphp_notice">
<h3 style="font-size : 18px;"><?php echo $error ?></h3>
<p>
Serverity: <?php echo $errno?>
</p>
<p>
File: <?php echo $file ?>
</p>
<p>
Line: <?php echo $line ?>
</p>
<p style="coler:#099">
KUAIXUEPHP开源框架 版本: <?php echo KUAIXUEPHP_VERSION ?>
</p>
</div>
尝试报错,看结果
如果是致命错误,那么这个方法也是无法执行,我们需要编写另外一个防止致命错误的方法
register_shutdown_function方法
register_shutdown_function这个函数是在PHP程序运行结束之前调用的,用这个函数可以做很多,比如调用运行发生致命错误中止的原因,或者调试程序的执行时间等。
final class Application{
public static function run(){
self::_init(); //初始化框架
set_error_handler(array(__CLASS__,'error'));
register_shutdown_function(array(__CLASS__,'fatal_error'));
self::_user_import();
self::_set_url();
spl_autoload_register(array(__CLASS__,'_autoload'));
self::_create_demo();
self::_app_run();
}
public static function fatal_error(){
}
我们来看一下error_get_last()函数
public static function fatal_error(){
if ($e = error_get_last()){
var_dump($e);
}
}
当发生致命错误时,结束前执行register_shutdown_function方法,然后调用
error_get_last()函数
[type] - 描述错误类型
[message] - 描述错误消息
[file] - 描述发生错误的文件
[line] - 描述发生错误的行号
我们改写出错方法,当致命错误时进入halt函数内。
如何来分辨什么是致命错误呢,什么是非致命错误呢???
我们根据$erron的数值也就是编号来分辨
非致命错误时,错误编号为2
致命错误时,错误编号为4
那我们重新改写error方法
public static function error($errno , $error , $file, $line){
switch ($errno){
case E_ERROR: //默认为1
case E_PARSE: //4
case E_CORE_ERROR: //8
case E_COMPILE_ERROR: //16
case E_USER_ERROR: //32
$msg = $error . $file . "第{$line}行";
halt($msg);
break;
case E_STRICT:
case E_USER_WARNING: //512
case E_USER_NOTICE:
default:
if(DEBUG){
include DATA_PATH . '/Tpl/notice.html';
}
break;
}
}
当再次进入错误方法时的四个参数如下:
并且致命错误页面与非致命错误页面返回不同
致命错误页面:
启用halt方法,并且计入日志
非致命错误页面
不计入日志
day28-模型类之连接数据库
我们需要编写一个模型类来操作数据库,然后只需要在C函数中调用参数即可,不用修改框架。
新建Model.class.php
使用all函数去查询数据库里的表
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2021-11-18
* Time: 19:01
*/
class Model{
//保存连接信息
public static $link = NULL;
//保存表名
protected $table = NULL;
//初始化表信息
private $opt;
//记录发送的sql
public static $sqls = array();
public function __construct($table=NULL){
$this->table = is_null($table) ? C('DB_PREFIX') . $this->table : C('DB_PREFIX') .$table;
//连接数据库
$this->_connect();
//初始化sql信息
$this->_opt();
}
public function query($sql){
self::$sqls[] = $sql;
$link = self::$link;
$result = $link->query($sql);
if($link->errno) halt('mysql错误 ' . $link->error . '<br/>SQL:' .$sql );
$row = array();
while($row = $result -> fetch_assoc()){
$rows[] = $row;
}
$result -> free();
$this->_opt();
return $rows;
}
public function all(){
$sql = "SELECT " . $this->opt['field'] . " FROM " . $this->table . $this->opt['where'] . $this->opt['group'] . $this->opt['having'] . $this->opt['order'] . $this->opt['limit'];
return $this->query($sql);
}
private function _opt(){
$this->opt = array(
'field' => '*',
'where' =>'',
'group' => '',
'having' => '',
'order' => '',
'limit' => ''
);
}
/**
* _connect连接
*/
private function _connect(){
if (is_null(self::$link)){
$db = C('DB_DATABASE');
if (empty($db)) halt('请先配置数据库');
$link = new Mysqli(C('DB_HOST'),C('DB_USER'),C('DB_PASSWORD'),$db,C('DB_PORT'));
if ($link->connect_error) halt('数据库连接错误,请检查配置项');
$link->set_charset(C('DB_CHARSET'));
self::$link = $link;
}
}
}
?>
config.php下
<?php
return array(
//配置项 =>配置值
'DB_CHARSET' => 'utf-8',
'DB_HOST' => '127.0.0.1',
'DB_PORT' => '3306',
'DB_USER' => 'root',
'DB_PASSWORD' => 'root',
'DB_DATABASE' => 'db2',
'DB_PREFIX' =>''
);
在入口处调用Model类(使用all函数去查询数据库里的表)
<?php
class IndexController extends Controller{
public function index(){
$obj = new Model('account');
$data = $obj->all();
var_dump($data);
}
}
当密码错误时会报错