欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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语句就算正式完成!