一、路由原理与实现
将模块、控制器和方法从pathinfo中解析出来
user.php
<?php
// 用模块当命名空间
namespace admin;
class User
{
public static function index($id,$name)
{
printf('id=%d,name=%s',$id,$name);
}
}
- 实例
<?php
require __DIR__.'/../helper.php';
// ! 主流路由解决方案:pathinfo
$url = 'http://phpedu.com/0507/router/demo2.php?c=user&a=hello';
p(pathinfo($url));
// 这个pathinfo不是我们要的
// 我们真正需要的是位于脚本名demo2.php与xxxx查询字符串之间的路径信息
$url2 = 'http://phpedu.com/0507/router/demo2.php/one/two/three?c=user&a=hello';
p(pathinfo($url2));
// p($_SERVER['PATH_INFO']);
// 以单一入口为例
// index.php?m=模块,例如前台home,后台admin
// 单入口
// index.php/模块/控制器/方法
// index.php/module/controller/action
// 多入口
// 前台:index.php 作为入口 不需要模块,controller/action
// 后台:admin.php 作为入口 不需要模块,controller/action
$url3 = 'http://phpedu.com/0507/router/demo2.php/admin/user/index';
p($_SERVER['PATH_INFO']);
p(explode('/',trim($_SERVER['PATH_INFO'],'/')));
$request = explode('/',trim($_SERVER['PATH_INFO'],'/'));
// 将模块、控制器和方法解析出来
[$module,$controller,$action] = $request;
printf('模块:%s<br>控制器:%s<br>方法:%s<br>',$module,$controller,$action);
// 从pathinfo中解析出参数
$url4 = 'http://phpedu.com/0507/router/demo2.php/admin/user/index/id/1/name/admin';
require 'User.php';
// admin\User::index(1,'张三');
// 类名
$className = $module.'\\'.ucfirst($controller);
p($className);
$params = array_splice($request,3);
printf('<pre>%s</pre>',print_r($params,true));
echo call_user_func_array([$className,$action],$params);
// p(array_chunk([1, 2, 3, 4, 5, 6, 7], 2));
$arr = array_chunk($params, 2);
p($arr);
$result = [];
foreach ($arr as $item) {
[$key, $value] = $item;
$result[$key] = $value;
}
p($result);
$result = array_filter($result);
p($result);
echo call_user_func_array([$className,$action],$result);
- 路由访问
二、视图基类
- 数据展示页面
<body>
<h3>User控制器的hello()方法</h3>
<h3>Hello,<?=$username?></h3>
<h3>Hello,<?=$items?></h3>
<h3>Hello,<?=$lang?></h3>
<ul>
<?php foreach($items as ['name'=>$name,'price'=>$price]) : ?>
<li><?=$name?> : <?=$price?> 元</li>
<?php endforeach ?>
</ul>
<ul>
<?php foreach($lang as $value) : ?>
<li><?=$value?></li>
<?php endforeach ?>
</ul>
</body>
- 视图基类
<?php
// 视图基类
namespace phpcn;
class View
{
// 约定:控制器方法的模板,默认一控制器为目录名,以方法为文件名
protected $controller;
protected $action;
protected $path;
// 模板变量容器
protected $data = [];
// 初始化时创建模板的路径
public function __construct($controller,$action,$path = '/view/')
{
$this->controller = $controller;
$this->action = $action;
$this->path = $path;
}
// 模板赋值
public function assign($name,$value){
// $name 是外部变量 在模板文件 中的变量名
// $value 就是 模板变量的值
$this->data[$name] = $value;
}
// 模板渲染
// 将模板赋值与模板渲染二合一
public function render($path='',$name=null,$value=null)
{
if($name && $value) $this->assign($name,$value);
// 展开模板变量数组
extract($this->data);
if(empty($path)){
// 按约定规则来生成模板文件的路径并加载它
$file = __DIR__ . $this->path . $this->controller .'/' . $this->action . '.php';
}else{
$file = $path;
}
file_exists($file) ? include $file : die('视图不存在');
}
}
// 测试
$controller = 'User';
$action = 'hello';
$view = new View($controller,$action);
// 模板赋值:变量
$view->assign('username','朱老师');
$items = [
['name'=>'手机','price'=>15000],
['name'=>'电脑','price'=>25000],
['name'=>'相机','price'=>35000],
];
$view->assign('items',$items);
// 渲染模板
// $view->render();
// 渲染,赋值二合一
$view->render($path = '', 'lang', ['php', 'java', 'python']);
三、模型与查询构造器基类
- Db模型
<?php
namespace phpcn;
use PDO;
class Db
{
protected $db;
protected $table;
protected $field;
protected $limit;
protected $opt = [];
public function __construct($dsn,$username,$password)
{
$this->db = new PDO($dsn,$username,$password);
}
public function table($table)
{
$this->table = $table;
// 返回当前对象,方便后面链式调用
return $this;
}
public function field($field)
{
$this->field = $field;
return $this;
}
public function limit($limit=10)
{
$this->limit = $limit;
$this->opt['limit'] = " LIMIT $limit";
return $this;
}
// 分页
public function page($page=1){
// 偏移量:offset = (page-1)*limit
$this->opt['offset'] = ' OFFSET '.($page-1)*$this->limit;
return $this;
}
// 查询条件
public function where($where = '')
{
$this->opt['where'] = " WHERE $where";
return $this;
}
}
- 查询构造器:查
// 查询
public function select()
{
// 拼装sql
$sql = 'SELECT '.$this->field.' FROM '.$this->table;
$sql .= $this->opt['where'] ?? null;
$sql .= $this->opt['limit'] ?? null;
$sql .= $this->opt['offset'] ?? null;
echo $sql.'<hr>';
$stmt = $this->db->prepare($sql);
$stmt->execute();
// 清空查询条件
$this->opt['where'] = null;
return $stmt->fetchAll();
}
$db = new Db('mysql:dbname=mydb','myshop','yzj123');
// $result = $db->table('staff')->field('id,name,email')->select();
$result = $db->table('staff')->field('id,name,email')
->where('id > 1')
->limit(2)
->page(3)
->select();
require 'helper.php';
p($result);
- 查询构造器:插入
// 插入
public function insert($data)
{
// [a=>1,b=2] 'a=1, b=2'
$str = '';
foreach($data as $key=>$value){
$str .= $key.' = "' . $value . '", ';
}
// $str.=',';
// rtrim() 函数移除字符串右侧的空白字符或其他预定义字符 rtrim(string,charlist)
$sql = 'INSERT '.$this->table.' SET '. rtrim($str,', ');
echo $sql.'<hr>';
$stmt = $this->db->prepare($sql);
$stmt->execute();
$this->opt['where'] = null;
return $stmt->rowCount();
}
$n = $db->table('staff')->insert(['name'=> 'zhu', 'email' => 'zhu@php.cn', 'sex' => 1, 'password' => md5(123456)]);
echo $n > 0 ? '新增成功<hr>' : '新增失败或没有数据被添加<hr>';
- 查询构造器:更新
// 更新
public function update($data)
{
// [a=>1,b=>2] 'a=1,b=2'
$str = '';
foreach($data as $key=>$value){
$str .= $key.' ="'.$value.'", ';
}
$sql = 'UPDATE '.$this->table.' SET '.rtrim($str,', ');
$sql .= $this->opt['where'] ?? die('禁止无条件更新');
echo $sql.'<hr>';
$stmt = $this->db->prepare($sql);
$stmt->execute();
$this->opt['where'] = null;
return $stmt->rowCount();
}
$n = $db->table('staff')->where('id = 10')->update(['name' => 'Mrs_K']);
echo $n > 0 ? '更新成功<hr>' : '更新失败或没有数据被更新<hr>';
- 查询构造器:删除
// 删除
public function delete()
{
$sql = 'DELETE FROM '.$this->table;
$sql.= $this->opt['where'] ?? die('禁止无条件删除');
echo $sql.'<hr>';
$stmt = $this->db->prepare($sql);
$stmt->execute();
$this->opt['where'] = null;
return $stmt->rowCount();
}
$n = $db->table('staff')->where('id = 10')->delete();
echo $n > 0 ? '删除成功<hr>' : '删除失败或没有数据被删除<hr>';