直接跑通新闻列表页面比看文档更高效,ci4.5.0关键在于:入口必须访问/public/路径、newsmodel需设置$allowedfields、控制器推荐构造函数注入requestinterface。

直接跑通一个带数据库读写的新闻列表页面,比看十页文档都管用。CI4.5.0 的关键不是“学完所有”,而是先让 index.php 能进 public/、Home::index() 能取到数据、NewsModel 能 update() 成功——卡在这三步,后面全瘫。
入口文件必须走 public/,否则 404 不报错只静默失败
CI4 把入口强制收进 public/ 目录,这是安全机制,不是可选项。直接访问 http://localhost/myapp/ 必然 404,但错误页可能空白或显示 Apache 默认页,根本不会提示你“该去 public 下”。
- 正确访问地址是
http://localhost/myapp/public/ - Apache 用户:确认
public/.htaccess存在且mod_rewrite已启用;如果没开,就老老实实用带/public/的 URL - Nginx 用户:server 块里必须有
root /path/to/myapp/public;和try_files $uri $uri/ /index.php?$query_string;,漏掉任一字段都会返回 404 - 别改
index.php位置,也别把它剪出来扔根目录——框架启动流程依赖public/index.php → bootstrap → services这条链
NewsModel 必须设 $allowedFields,否则 update() 无声失败
CI4 的模型默认拒绝写入任何字段,除非显式列入 $allowedFields。不设它,调 $model->update(1, $data) 看似执行了,实际 SQL 里 set 部分为空,数据库一行不变,也不报错。
- 在
app/Models/NewsModel.php中,至少声明:protected $allowedFields = ['title', 'content', 'slug']; - 主键字段(如
id)不用写进$allowedFields,但更新时 WHERE 条件仍需传入,比如$model->update(123, $data) - 如果字段名含下划线(如
created_at),且启用了$useTimestamps = true,记得同步设$createdField = 'created_at',否则时间戳不会自动写入 - 调试时可在控制器里加
var_dump($model->getLastQuery());查看最终生成的 SQL,确认 set 后有没有字段
构造函数注入 RequestInterface 比 $this->request 更稳
新手常在控制器里直接用 $this->request->getPost(),这没问题;但一旦涉及单元测试或需要替换请求来源(比如 CLI 调用),硬编码访问就会崩。CI4.5.0 推荐用构造函数参数注入,框架自动解析,更可控。
- 写法示例:
public function __construct(RequestInterface $request) { $this->request = $request; } - 注意:不要手动调
parent::__construct(),CI4 的Controller基类已处理好服务容器初始化 - 如果同时要注入多个服务,顺序无关,框架按类型匹配:
public function __construct(RequestInterface $request, ResponseInterface $response, SessionInterface $session) - 自定义服务(如
UserAuth)也能注入,前提是已在app/Config/Services.php中注册或通过Services::injectMock()绑定
真正容易被忽略的是 $allowedFields 的字段名必须和数据库列名完全一致——大小写敏感、不能多空格、不能用别名。哪怕只差一个下划线,update() 就变成无效操作,连日志都不会记。动手前先 DESC news 看一眼字段名,比事后查半小时更省时间。











