PHP分层架构简单示例(1.业务逻辑类)
对于一些大型项目,分层可以分离代码关注点,可以让不同的技术人员协同开发,对代码的更改和维护也具有极大的优势,此后也可以方便的更换组件,不用推到整个项目,比如常见的更换数据库的场景。分层的项目一般多采用.NET或Java技术,而对于PHP比较少一些,可能由于PHP的大型项目偏少以及PHP一般不做后端的方向,这篇文章简单的写一个PHP分层的示例。
定义一个最简单的业务场景,发布博客,为了简单化,我们认为博客的数据表只有主键Id、标题、内容和发布时间。对于这个数据表,我们先抽象出最简单业务逻辑类。
View Code
<?php
class Blog
{
private $Id; //主键
private $Title; //标题
private $Content; //内容
private $PubTime; //发布时间
}
?>
由于要对上述的一些字段做一些校验,我们对上述字段私有,再设置一些公开访问来操作这些字段,为了更好的提示验证过程中的错误,我们设置一个错误验证数组,来存储相应的错误,后边可以根据相应的要求来显示错误。
<?php
class Blog
{
private $Id; //主键
private $Title; //标题
private $Content; //内容
private $PubTime; //发布时间
public $errors=array(); //错误数组
//对ID的封装
function GetId()
{
return $this->Id;
}
function SetId($id)
{
try {
if (empty($id))
throw new Exception("ID不能为空");
if (!is_int($id))
throw new Exception("ID应为数字");
if ($id <= 0)
throw new Exception("ID应为正数");
$this->Id = $id;
}catch (Exception $e)
{
$this->errors['Id']=$e->getMessage();
}
}
//对Title的封装
function GetTitle()
{
return $this->Title;
}
function SetTitle($title)
{
try {
if (empty($title))
throw new Exception("标题不可为空");
if (!is_string($title))
throw new Exception("标题应为字符串");
if (strlen($title)>60)
throw new Exception("标题请小于20个汉字!");
$this->Title = $title;
}catch (Exception $e)
{
$this->errors['Title']=$e->getMessage();
}
}
//对Content的封装
function GetContent()
{
return $this->Content;
}
function SetContent($content)
{
try {
if(empty($content))
throw new Exception("内容不能为空");
$this->Content = $content;
}catch (Exception $e)
{
$this->errors['Content']=$e->getMessage();
}
}
//对PubTime的封装
function GetPubTime()
{
return $this->PubTime;
}
function SetPubTime($pubTime)
{
try {
if (empty($pubTime))
throw new Exception("时间不能为空");
$this->PubTime = $pubTime;
}catch (Exception $e)
{
$this->errors['PubTime']=$e->getMessage();
}
}
}?>
到这里一步,该对这个类加一些业务操作方法,这里我们只用最简单的增加一篇博客,修改一篇和查看一篇博客的操作方法,对于Blog类扩充后代码为:
View Code
<?php
class Blog
{
private $Id; //主键
private $Title; //标题
private $Content; //内容
private $PubTime; //发布时间
public $errors=array(); //错误数组
//对ID的封装
function GetId()
{
return $this->Id;
}
function SetId($id)
{
try {
if (empty($id))
throw new Exception("ID不能为空");
if (!is_int($id))
throw new Exception("ID应为数字");
if ($id <= 0)
throw new Exception("ID应为正数");
$this->Id = $id;
}catch (Exception $e)
{
$this->errors['Id']=$e->getMessage();
}
}
//对Title的封装
function GetTitle()
{
return $this->Title;
}
function SetTitle($title)
{
try {
if (empty($title))
throw new Exception("标题不可为空");
if (!is_string($title))
throw new Exception("标题应为字符串");
if (strlen($title)>60)
throw new Exception("标题请小于20个汉字!");
$this->Title = $title;
}catch (Exception $e)
{
$this->errors['Title']=$e->getMessage();
}
}
//对Content的封装
function GetContent()
{
return $this->Content;
}
function SetContent($content)
{
try {
if(empty($content))
throw new Exception("内容不能为空");
$this->Content = $content;
}catch (Exception $e)
{
$this->errors['Content']=$e->getMessage();
}
}
//对PubTime的封装
function GetPubTime()
{
return $this->PubTime;
}
function SetPubTime($pubTime)
{
try {
if (empty($pubTime))
throw new Exception("时间不能为空");
$this->PubTime = $pubTime;
}catch (Exception $e)
{
$this->errors['PubTime']=$e->getMessage();
}
}
//增加
public function AddOne($title, $content, $pubTime, $newsClassId)
{
$news = new News();
$news->SetTitle($title);
$news->SetContent($content);
$news->SetPubTime($pubTime);
$news->SetNewsClassId($newsClassId);
return $news->Save();
}
//修改
public function UpdateOne($id, $title, $content, $pubTime, $newsClassId)
{
$news = new News();
$news->SetId($id);
$news->SetTitle($title);
$news->SetContent($content);
$news->SetPubTime($pubTime);
$news->SetNewsClassId($newsClassId);
return $news->Save();
}
//和数据库交互
private function Save()
{
//和数据库交互前检查错误
Error::CheckErrors($this->errors);
//BlogData为相应的数据访问类
$BlogData = new BlogData();
if ($this->Id > 0) //根据是否有Id判断是增加博客还是修改
{
return $BlogData->UpdateOne($this);
}else
{
$this->SetPubTime(date("Y-m-d H:i:s"));//将发布时间设为现在
return $newsData->InsertOne($this);
}
}
public function GetOne($id)
{
try
{
if(!preg_match('/^[0-9]+$/',$id))
throw new Exception("Id必须为整数");
$BlogData = new BlogData();
$result= $BlogData->GetOne($id);
if(empty($result))
{
//若没有找到,跳转到未找到页面
header('404.html');
}
else
{
//找到的话返回结果
return $result;
}
}
catch (Exception $e)
{
$this->errors[]="<li>".$e->getMessage()."</li>";
Error::CheckErrors($this->errors);
}
}
}
?>
可以看到,增加和修改方法都是在构造一个Blog对象,在构造的过程中一些业务逻辑就会被字段规则给验证,而错误会被记录在$errors数组中,对于AddOne()和UpdateOne()方法,最终都调用了本类的一个Save()方法。而Save()则根据当前Blog对象是否有Id这个字段有值来选择是调用数据访问类的增加还是更新方法,可以减少耦合。
在入库之前,我们应该保证非法数据不能入库,这时$errors数组就可以用上,我们可以根据它是否为空来决定数据是否写入数据库中,这里调用这段代码:
Error::CheckErrors($this->errors);
Error是一个处理错误类,代码如下
View Code
<?php
class Error
{
//构建静态方法,若有错误,显示错误,后续程序中断
static public function CheckErrors($errors)
{
if(!empty($errors))
{
//将所有错误信息输出
$finalerror=NULL;
foreach($errors as $error)
{
$finalerror=$finalerror.strip_tags($error)."\\r\\n";
}
$len = strlen($finalerror);
$finalerror = substr($finalerror,0,$len-4);
echo"<script>alert('".$finalerror."');</script>";
//当错误不为空时,程序中断
exit(0);
}
}
}
?>
这个做的比较简单,若有错误就弹出相应的警告框,程序终止,不太友善,可以根据相应的需求来改善。
到这里,简单的业务逻辑类就算完成,下一步我们将构造相应的数据访问类。