PHP常用的显示与逻辑分离思想
程序员文章站
2024-03-25 23:51:10
...
- 显示与逻辑相分离思想
提出需求:
在页面上,显示“当前时间”。
原始做法:显示与逻辑混合
(文件名为一个:show_time.php)
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<?php
$time = date("Y-m-d H:i:s");
?>
<h2>当前时间: <?php echo $time; ?></h2>
</body>
</body>
</html>
显示与逻辑相分离做法:
2个文件
<?php
$time = date("Y-m-d H:i:s");
include './show_time.html'
?>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<h2>当前时间: <?php echo $time; ?></h2>
</body>
</body>
</html>
模板技术
需求:
显示当前时间,并可以由用户来选择使用不同的风格进行显示;
基本做法:
获取数据的逻辑基本保持不变!
而:
表现数据的文件,可以有多个!
我们只要在php文件中,根据用户的“选择”(请求),以决定使用(载入)哪个模板文件;
逻辑文件(php)为:
<?php
//获取数据
$time = date("Y-m-d H:i:s");
if(!empty($GET["color"])){
$ban = $GET["color"];
}else {
$color = "red";
}
$file = "./show_time_".$color.".html";
include $file;
?>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<p>
<a href="show_time.php?color=red">Red</a>
<a href="show_time.php?color=green">Red</a>
<a href="show_time.php?color=blue">Red</a>
</p>
<h2>当前时间: <?php echo $time; ?></h2>
</body>
</body>
</html>
- mvc思想原理
MVC框架思想原理
控制器:
Controller,是一个php文件,由浏览器直接请求(访问);
它需要做2件最核心的工作:
1,(根据请求),决定需要什么数据,并去调用模型文件(类),去获取该数据;
2,(根据请求),决定需要将数据显示在哪个视图文件中。
模型:
Model,是一个php文件,不能直接请求,只能“被载入”而发挥作用。
它的核心工作只有一个:
(根据控制器的要求)去生产数据;
视图:
View,是一个“伪html文件”(因为其中有极简单的php代码),它也不应由浏览器直接请求;
它的作用是:
结合html和css代码,显示相应的变量(数据)
模型层(Model)的典型实现
模型层的主要作用:
用于处理数据的存取操作,比如表的增删改查;
通常都是根据“控制器的要求”,以返回合适的数据;
有时候,控制器还需要“传递过来”相应的数据,才能获取对应的结果数据;比如:
获取id为5的用户的信息,此时控制器就需要传递过来“5”这个数据;
模型层的典型代码模式
class 模型类名{
function 方法1(){。。。}
function 方法2(){。。。}
function 方法3(){。。。}
。。。。。。。
}
说明:
1,每个方法,都是为了获取“某种数据”;
2,有的方法,可能需要一些参数(形参);
3,这些方法,通常都需要跟数据库打交道,则就都需要“mysqldb”工具类及相关的数据库连接数据;
控制器中调用模型层获取数据的典型做法
require ‘模型层类文件’;
$obj = new 模型对象();
$data = $obj->某个方法();
//例子
M:
<?php
class MyDateTime{
function GetDate(){
return date("Y-m:d H:i:s");
}
function GetTime(){
return date("H:i:s");
}
function GetDateTime(){
return date("Y year m Month d day H:i:s");
}
}
?>
V:
<body>
<p align="right">
<a href="mvc_time_demo.php?q=date">style1</a>
<a href="mvc_time_demo.php?q=time">style2</a>
<a href="mvc_time_demo.php?q=datetime">style3</a>
</p>
<div class="time"><?php echo time ?></div>
</body>
C:controller
<?php
require('./dateTime.class.php');
if(!empty($GET["q"]) && $GET["q"] == "time"){
$obj = new MyDateTime();
$time = $obj->GetTime();
}else if(!empty($GET["q"]) && $GET["q"] == "date"){
$obj = new MyDateTime();
$time = $obj->GetDate();
}else {
$obj = new MyDateTime();
$time = $obj->GetDateTime();
}
include './mvc_time_demo.html'
?>
控制器的典型实现
控制器的作用
• 获取请求数据
• 根据请求信息,以决定,调用哪个模型以获取什么数据;
• 根据请求信息,载入哪个视图文件以显示该(些)数据
控制器类的常规做法
其功能:
1,用于获取用户的请求数据,
2,(或)获取模型数据,
3,显示到视图中——或也可能直接输出;
控制器的划分
通常,一个项目中,会有很多很多的功能,我们通常会将一些“相关功能”,合在一起,称为“一个模块”,并使用一个控制器去“表达”这个模块中的各个功能——其实就是方法。
控制器中的“动作”:
一个控制器,就是一个类;
一个控制器中,就只包含了一些方法!!!
那么, 这些方法,被称为“动作”——因为每个方法,一定就对应了网页界面上用户所在的某个“操作”(动作,请求);
习惯上,所有的动作(方法),都以“Action”这个词为结尾。
这些动作(方法名),将会对应网页上的连接(或跳转或提交)动作中的“act”参数的值!
基础控制器类
一个项目中,有多个控制器!
每个控制器是一个类文件!
每个控制器中都有各自的一些功能——方法——动作!
但:
他们常常,有一些共同的工作或事情要去做:
1,设定编码!
因为是由控制器来决定显示什么数据,也就应该由其来决定使用什么编码!
一般来说,每一个网站(项目/软件)产品,通常都是使用一种相对固定的编码。
则他们应该可以进行“统一设置”;
2,页面的简短消息(提示文字)的显示,以及跳转功能。
这也是常见的通用功能。
class BaseController{
function __construct(){
header("Content-Type:text/html;charset=utf-8");
}
function GotoUrl($msg,$url,$time){
echo "<font color=red>$msg</font>"
echo "<br /><a href='$url'>back</a>";
echo "<br />page jump after {$time}";
header("refresh:$time;url=$url");
}
}
视图层的典型做法
• 功能:展示页面的静态内容,以及相关的变量数据。
• 数据分为:
o 普通标量数据:echo $v1;
o 数组数据:foreach($arr as $key => $value){....}
• 或单独输出:echo $arr[‘id’]; echo $arr[‘age’]; .....
o 对象数据: echo $obj->p1; echo $obj->p2;
有关MVC的其他常见做法
请求分发器(前端控制器)
有没有可能,使用一个参数,在每次请求的时候,都带上“要使用的”控制器名?
如果可以,则,我们就可以将代码进一步“提升”(简化为):
$c = “User”; //它也可能是“product”,或其他。。。
require ‘./” . $c . “Model.class.php’;
require './ModelFactory.class.php'; //这个都一样,不同动
require './BaseController.class.php';//这个都一样,不同动
class XXXController extends BaseController{ ...... } //代表某个控制器,每个控制器是一个独立文件
require ‘./’ . $c . “Controller.class.php”; //这里才是需要载入的“当前控制器类”
$controller_name = $c . “Controller”; 构建控制器的类名
$ctrl = new $controller_name (); //可变类
$act = !empty($_GET['a']) ? $_GET['a'] : "Index";
$action = $act . "Action";
$ctrl->$action();
这就是,所谓的前端控制器(请求分发器):
它的作用是:
1,根据传过来的c请求数据,决定使用哪个控制器;——有默认值,目前为User
2,根据传过来的a请求数据,决定使用哪个动作(方法);——有默认值,目前为Index
而且,此时,UserController类和ProductController类中,没有其他代码了,只有“纯类”的定义代码;
目录结构的设定:
通常,我们会将一个MVC项目中的一些一些相应的文件,分门别类存放,结果就类似这样:
MVC项目/
index.php
/Controllers/
XX1Controller.class.php
XX2Controller.class.php
.....
/Models/
XX3Model.class.php
XX4Model.class.hpp
.....
/Views/
page1.htm.
page2.html
.....
/Framework/
BaseController.class.php
BaseModel.class.php
ModelFactory.class.php
MySQLDB.class.php
平台的划分
平台是什么?
平台只是人们都一个“网站群”的更大范围的划分,最常见的,就是,一个网站,几乎总是分为:
前台:
后台:
合作伙伴平台:
.......
平台,实际单词是“platform”,但在目录结构中,也常用Application(应用),因为,通常认为,一个平台,就是一个“应用”;
在应用中,这些平台,都会需要用到一些“共同的东西”,比如:
基础模型类;
基础控制器类;
数据库操作工具类;
........
那么,我们也可以将他们进一步“聚合”,聚合为一个“大的MVC”框架下的多个相对独立的“站点”;
因此,我们的整个MVC框架,又可以进一步提示为:
MVC框架/
index.php
/Framework/ //这是所有平台的公共的基础的部分
BaseController.class.php
BaseModel.class.php
ModelFactory.class.php
MySQLDB.class.php
/Application/ //这是所有平台的总目录
/front/ //前台
/Controllers/
/Modelss/
/Views/
/back/ //后台
/Controllers/
/Modelss/
/Views/
/partner/ //合作伙伴平台
/Controllers/
/Modelss/
/Views/
相应的,其中的所有请求(链接/提交/跳转),都又得加上平台的信息了!
所有用户列表的视图中添加一个链接
然后,在back平台,分别建立3个目录,及对应文件:
back/
/Controllers/
AdminController.class.php
/Models/
AdminModel.class.php
/Views/
Login.html
基础常量的设定
我们在mvc中,会用到很多“相对固定的目录路径”,使用一个常量来表示,常常能够简化代码!
在inde.php页面中:
相应的,其他一些需要载入文件的位置(主要是“控制器”中载入视图)
1,自动加载是指:在需要一个类的时候,自动去加载该类的对应类文件;
2,自动加载,不能自动加载“视图文件”;
禁止其他目录中文件的直接访问
找到站点www.php.com的配置中的“目录权限设置项
重启apache。
然后,在mvc框架的application目录和framework目录下,都放置一个相同的文件(.htaccess),
其内容为(只有一行):
Deny from All
- PDO
PDO是什么?
PDO是别人写的“数据库操作工具类”!——它可以代替我们自己写的MySQLDB.class.php.
使用它,类似这样:
$pdo = new PDO(连接信息);
$sql = “select * from .....”;
$result = $pdo->query($sql); //返回一个“pdo结果集”;
$sql = “delete / update / insert ........ ”;
$result2 = $pdo->exec($sql); //返回一个真假值;
即,要操作某种数据,就得去“打开”对应的pdo引擎。
pdo引擎,在哪里打开?
——在php.ini的配置文件中,无非就是一个“模块”而已,
使用pdo连接mysql数据库
• $DSN = "mysql:host=服务器地址/名称;port=端口号;dbname=数据库名";
• $Opt = array(PDO::MYSQL_ATTR_INIT_COMMAND=>’set names 连接编码’);
• $pdo = new pdo($DSN, "用户名", "密码", $Opt);
可见,返回来的就是一个pdo类的对象。
pdo对象的使用(常见方法)
$result = $pdo->query(“返回结果集的sql语句”); //对比最原始的函数: mysql_query(“select ..... “)
结果:
成功:就是一个pdo结果集对象(后续马上学习);
失败:false;
$result = $pdo->exec(“增删改的sql语句”);
结果: true(表示成功),false(表示失败);
$pdo = null; //销毁该对象;
其他操作:
• $pdo->lastInsertId();
o 获取最后添加的id值;
• $pdo->beginTransaction();:
o 开启一个事务
• $pdo->commit()
o 提交一个事务
• $pdo->rollBack();
o 回滚一个事务;
• $pdo->inTransaction();
o 判断当前行是否在事务中,返回true/false
• $pdo->setAttribute(属性名,属性值);
o 设置pdo对象的属性值;
o 举例:$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)
$pdo->begintrsaction();
$pdo->exec(“insert ....”);
$pdo->exec(“delete ....”);
$v1 = $pdo->intransaction(); //结果是true
pdo的错误处理
静默模式
默认情况下,pdo采用“静默模式”处理错误:
就是发生了错误后,并不提示,而只是返回false。我们需要在程序中去判断返回是否为fale,然后,如果是false,再去“主动”获取错误信息。——跟mysql一样!
对比mysql:
$sql = “updateeeee tab set name = ‘abc’ ; ”;
$result = mysql_query($sql); //这里,执行该sql语句,肯定出错
if( $result === false){
echo “发生错误:” . mysql_error();
}
else{......}
则对pdo来说,大致如此:
$sql = “updateeeee tab set name = ‘abc’ ; ”;
$result = $pdo->exec ($sql); //这里,执行该sql语句,肯定出错
if( $result === false){
echo “发生错误:” . $pdo->errorInfo(); //这里只是示意;
//实际情况是:$pdo->errorInfo()返回的是一个“数组”,其中的下标为3的项,才是错误提示内容
}
else{......}
异常模式
可以简单理解为:适应面向对象语法的处理错误的一种语法结构。如下所示:
try{
在这里,可以执行“可能出错”的语句(多条也可以);
一旦发生错误,就会终止当前范围的后续程序执行,
而立即跳转到catch部分——处理错误!
}
catch( Exception $e ){
//一旦发生错误,就会进入这里,此时,并会生成一个“错误对象”;
//该错误对象,就是系统类Exception的一个实例:它包含了错误信息。
}
pdo要使用异常模式,就得专门设置(因为其默认是静默模式):
pdo的结果集对象(PDOStatement)
pdo的结果集对象从哪里来?
——来自pdo对象执行“返回数据集的sql语句”并成功的时候,得到的就是pdo的结果集对象。
$stmt = $pdo->query(“select ..... “); //如果执行成功,则$stmt就是pdo的结果集对象
pdo结果集对象的常用方法
• $stmt = $pdo->query(“select ...... ”);//这是获得结果集
• $stmt->rowCount() ; //得到结果集的行数
• $stmt->columnCount() ; //得到结果集的列数
• $stmt->fetch( [返回类型] ); //从结果集中取出“一行”数据;
取出的结果,由其中的“返回类型”来决定,常用的有:
PDO::FETCH_ASSOC:表示关联数组
PDO::FETCH_NUM:表示索引数组
PDO::FETCH_BOTH:表示前二者皆有,这是默认值
PDO::FETCH_OBJ:表示对象
• $stmt->fetchAll([返回类型]);一次性获取结果集中的所有数据,返回的是一个二维数组,相当于我们自己写的GetRows()
• $stmt->fetchColumn( [$i] );获取结果集中的“下一行”数据的第$i个字段的值,结果是一个“标量数据”,相当于我们自己的写的:GetOneData()
• $stmt->fetchObject();
• $stmt->errorCode();:pdo结果集的错误代号
• $stmt->errorInfo(); pdo结果集的错误信息(是一个数组)
• $stmt->closeCursor(); 关闭结果集(相当于mysql_close())
pdo中的预处理语法
什么叫预处理语法
就是,为了“重复执行”多条结构类似的sql语句,而将该sql语句的形式“进行预先处理”(编译);
该sql语句的“形式”中,含有“未给定的数据项”。
然后,到正式执行的时候,只要给定相应的形式上的“数据项”,就可以更快速方便执行。
比如(有两种预定义语法):
语法1:
$sql = “select * from tab where id = ? “; //这里这个“?”就是未给定的数据项;这里通常叫做“占位符”
//也可以是多个问好。
语法2:
$sql = “select * from tab where id = :v1 and name = :v2 “; //这里这个“:v1”和 “:v2” 就是未给定的数据项;通常这里叫做“命名参数”;
怎么使用?
分3步:
1,对含预处理语法的sql语句进行“预处理”:
$stmt = $pdo->prepare( $sql ); //
2, 对上述预处理的结果对象($stmt)的未赋值数据,进行赋值:
$stmt->bindValue( 数据项1, 值1);
$stmt->bindValue( 数据项2, 值2);
。。。。。。
3, 执行执行:
$stmt->execute();
这样之后,该sql语句就算正式完成!
上一篇: 方法定义回顾
下一篇: 多线程系列八-ThreadLocal