同学们可能会跟我一样,老是看不懂别人讲解mvc的技术博客,路人的我就用php来撸一串代码,用例子来讲解什么是mvc,保证小学生都看懂。
首先展示项目的所有文件,安装xampp,执行puremvc.sql的语句,即可运行该项目,访问http://localhost/pureMVC/h5/game/lottery/home
跟一般的mvc框架一样,入口文件是index.php,我们先查看autoload.php文件
function app_autoload($className)
{
$file = __DIR__."\\app\\".$className.".php";
require_once $file;
}
spl_autoload_register("app_autoload");
autoload.php代码的意思是app文件下的所有文件都支持PSR-4标准,而views是不支持的。下面是index.php入口文件的全部代码
//第一件事 支持PSR-4
include __DIR__."/autoload.php";
define('ROOT_PATH',__DIR__);
//第二件事 解析url地址分割为控制器类和方法
$arrUri = parse_url($_SERVER['REQUEST_URI']);
$path = str_replace("/","\\",$arrUri['path']);
$pos = strrpos($path,"\\");
$controllerClass = "Controllers".substr($path,0,$pos);
$actionClass = substr($path,$pos+1);
$instance = new $controllerClass();
$method = new ReflectionMethod($instance, $actionClass);
//第三件事执行方法
echo $method->invoke($instance);
我们的例子简化步骤,只做了三件事,最后的原理都是一样,执行控制器的方法,按着思路我们来查看控制器的代码
//PSR-4标准的写法 命名空间形式
namespace Controllers\h5\game;
use Controllers\Controller;
use Services\LotteryService;
class lottery extends Controller
{
public function home()
{
//实例化一个抽奖业务逻辑并且调用获取奖品的方法
$prizes = (new LotteryService)->getPrizes();
$data = array(
'products'=>$prizes,
'level'=>2,
);
//渲染视图
return $this->view('lottery',$data);
}
}
home()方法实现了我们想要的结果,为了理解它的原理,我们分两步去解析。
第一步,先查看业务逻辑LotteryService.php
namespace Services;
use Models\Product;
class LotteryService
{
public function getPrizes()
{
$product = new Product;
$arrProduct = $product->select();
return $arrProduct;
}
}
发现它的getPrizes()方法是Product的模型执行select方法,点击Product类进来
namespace Models;
class Product extends ORM
{
public function __construct()
{
parent::__construct();
$this->table('product');
return $this;
}
}
这里的Product其实是对应数据库product这张表,继承ORM这个模型,说明是对象关系映射,整个过程可以发现,$prizes其实是把product表的数据全部获取组合成一个对象
第二步,查看$this->view方法
namespace Controllers;
class Controller
{
public function view($filename,$data=array())
{
$cacheFile = ROOT_PATH.'/views/cache/'.$filename.'.blade.php';
$content = file_get_contents(ROOT_PATH.'/views/'.$filename.'.blade.php');
//变量
$content = preg_replace('/\{\{\s*(.*?)\s*\}\}/i', '<?php echo ${1}; ?>', $content);
//foreach语句处理
$content = preg_replace('/@foreach\s*\((.*?)\)/i', '<?php foreach(${1}) { ?>', $content);
$content = preg_replace('/@endforeach/i', '<?php } ?>', $content);
file_put_contents($cacheFile,$content);
//打开输出控制缓存
ob_start();
extract($data);
require_once($cacheFile);
$output = ob_get_clean();
return $output;
}
}
每一个控制器都有view方法,(1)读取views文件夹的lottery.blade.php,(2)然后正则匹配替换掉@foreach @endforeach等特殊标签,(3)extract将数组的key转换为变量,(4)缓存文件,然后require_once执行缓存文件里面的php代码,(5)最后打印出来成html
查看views/lottery.blade.php代码,采用blade模板的写法,在phpstorm写代码竟然可以智能提示,比smarty模板强大多了
<h1>循环例子</h1>
@foreach($products as $product)
{{$product->title}}<br/>
@endforeach
查看缓存文件views/cache/lottery.blade.php代码
<h1>循环例子</h1>
<?php foreach($products as $product) { ?>
<?php echo $product->title; ?><br/>
<?php } ?>
做安卓或者ios的开发者会有mvp的概念,在php里面,会建立Presenter层,将@foreach到@endforeach的代码进行封装,使用一个对象方法来展示,这时也叫做mvp。