要让ThinkPHP路由参数直接参与数据库查询,必须打通路由定义、控制器接收、模型查询三环节:在route/app.php用Route::get()定义带:id变量的路由并设merge_rule为false;控制器中用param('id')获取并转整型校验;再用Db::table()或模型类Product::find($id)查询,联表时用join()配合路由参数过滤。

要让ThinkPHP的路由参数直接参与数据库查询,比如访问/product/123就查出ID为123的商品数据并渲染页面,必须打通路由定义、控制器接收、模型查询三环节,漏掉任一环都会导致404或空数据。
定义带变量的路由规则
在route/app.php中注册一条含命名变量的GET路由,不要用隐式匹配或正则兜底——那样会让参数无法自动注入控制器方法。
使用Route::get()明确声明请求类型,避免POST误触发:
use think\facade\Route;
立即学习“PHP免费学习笔记(深入)”;
Route::get('product/:id', 'Index/product')->option(['merge_rule' => false]);
其中:id是占位符,框架会自动将其作为字符串参数传入Index控制器的product方法;【option中的merge_rule必须设为false】,否则当存在同名静态路由时,该变量路由可能被忽略。
在控制器中接收并校验路由参数
进入app/controller/Index.php,编写product方法:
第一步:用$this->request->param('id')获取路由变量,不要用input()或get()——它们依赖URL查询字符串,而:id是路径段,只走param()。
第二步:强制转为整型并判断有效性:
$id = (int)$this->request->param('id');
if (!$id || $id <br><code> return $this->error('商品ID无效');}
这一步不能跳过。若直接拿字符串'123'去查数字主键,MySQL虽会隐式转换,但PDO预处理可能报错,且易被注入绕过。
用Db类执行带条件的单条查询
方法一:链式调用Db::table()
$data = Db::table('product')->where('id', $id)->find();
注意:此处table()只设物理表名,不加别名;where()字段名不带前缀,因未联表。
方法二:使用模型类(推荐)
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
先确保已定义app/model/Product.php模型,并设置正确表名:
class Product extends Model{ protected $table = 'product';}
再在控制器中调用:
$data = Product::find($id);
这行代码会自动做主键校验和缓存处理,比裸Db更安全。若返回null,说明数据库无此记录,需主动处理:
if (!$data) { return $this->error('商品不存在', '', 404);}
联表查询并用路由参数过滤关联字段
当需要查“分类名为‘手机’的商品列表”,且URL形如/category/phone时,必须用join(),with()无法实现条件筛选。
第一步:定义路由
Route::get('category/:name', 'Index/category');
第二步:在Index/category方法中获取:name参数:
$catName = $this->request->param('name');
第三步:显式指定主表别名,再用join()连接分类表:
$list = Db::table('product p') ->join('category c', 'p.cat_id = c.id') ->where('c.name', $catName) ->field('p.id,p.title,p.price,c.name as cat_name') ->select();
【join()参数必须是二维数组或字符串,不可混用】,这里用字符串写法最简洁;若后续要加第三个表,必须改用二维数组写法,否则框架报错。
第四步:将结果赋值给模板并输出:
$this->assign('list', $list);return $this->fetch();


















