PHP报错:非对象上下文使用$this问题求助
问题分析与解决方案
首先,你遇到的Uncaught Error: Using $this when not in object context报错,核心原因是在静态方法里调用了依赖对象上下文的实例方法,再加上你的类设计有几个关键问题,导致代码无法正常运行。下面是具体的修复步骤和优化建议:
1. 核心报错原因:静态方法与实例方法的冲突
你的User类里的getUsers()、getOneLevel()等都是静态方法,里面用self::all()、self::query()调用Model类的实例方法。但实例方法(比如all())依赖$this->table、$this->con这些对象属性,静态上下文没有对象实例,自然会报错。
解决思路:把User的静态方法改为实例方法,通过实例化User来调用方法;或者重构Model的方法为静态,但前者更符合面向对象的设计。
2. 逐个修复你的类
修复Connect类(数据库连接)
原来的Connect类只是创建了连接,但没有把连接对象保存下来,导致Model无法拿到真正的mysqli连接。同时修正错误的错误函数名:
<?php namespace Core; class Connect { private const DB_NAME = "vp_test"; private const DB_USER = "root"; private const DB_PASSWORD = ""; private const DB_HOST = "localhost"; public $connection; // 保存mysqli连接对象 public function __construct() { $this->connection = mysqli_connect(self::DB_HOST, self::DB_USER, self::DB_PASSWORD, self::DB_NAME); if (!$this->connection) { die("Connection error: " . mysqli_connect_error()); // 修正为mysqli的错误函数 } } }
修复Model类(基础模型)
修正连接获取方式,用$this调用实例方法,同时优化execute方法的返回值(原来只返回一行数据,无法处理多条结果):
<?php namespace Core; use Core\Connect; class Model { protected $con; // 改为protected,让子类可以访问 public $table; public function __construct() { $connectInstance = new Connect; $this->con = $connectInstance->connection; // 获取真正的mysqli连接 } public function all(){ $sql = "SELECT * FROM {$this->table}"; return $this->execute($sql); // 用$this调用实例方法,而非self } public function query($select, $where = false){ $sql = "SELECT {$select} FROM {$this->table}"; if ($where) { $sql .= " {$where}"; } return $this->execute($sql); } public function find($id){ return $this->query("*", "WHERE id = {$id}"); } protected function execute($sql){ // 改为protected,允许子类访问 $query = mysqli_query($this->con, $sql); if (!$query) { die("SQL Error: " . mysqli_error($this->con)); // 增加SQL错误提示 } // 根据结果行数返回对应格式:多条返回数组,单条返回关联数组 return mysqli_num_rows($query) > 1 ? mysqli_fetch_all($query, MYSQLI_ASSOC) : mysqli_fetch_assoc($query); } }
修复User类(业务模型)
去掉冗余的Model实例化,调用父类构造函数,将静态方法改为实例方法,补充缺失的return语句,同时修正SQL中的引号问题:
<?php namespace App; use Core\Model; class User extends Model { public function __construct() { parent::__construct(); // 必须调用父类构造,初始化数据库连接 $this->table = "users"; // 直接设置父类的public属性,无需额外实例化Model } public function getUsers(){ return $this->all(); // 用$this调用父类的实例方法 } public function getOneLevel($level){ return $this->query("*", "WHERE level = {$level}"); } public function getLevel($id){ return $this->query("level", "WHERE id = {$id}"); // 补充return } public function getParent($id){ $child = $this->find($id); // 注意:这里要给字符串加单引号,避免SQL语法错误 $parentId = $this->query("id", "WHERE username = '{$child["sponsor_username"]}'"); return $this->find($parentId['id']); // 补充return,取到父ID后查询父信息 } public function getChildren($id){ $parent = $this->find($id); return $this->query("*", "WHERE sponsor_username = '{$parent["username"]}'"); // 补充return } }
3. 正确使用方式
现在你可以通过实例化User类来调用方法,避免静态上下文的问题:
// 示例代码 $userModel = new App\User(); // 获取所有用户 $allUsers = $userModel->getUsers(); // 获取指定等级的用户 $level1Users = $userModel->getOneLevel(1); // 获取某个用户的上级 $parentUser = $userModel->getParent(1);
额外建议:避免SQL注入
当前代码直接把变量拼接到SQL中,存在严重的SQL注入风险。建议使用mysqli预处理语句,比如把find方法改为:
public function find($id){ $sql = "SELECT * FROM {$this->table} WHERE id = ?"; $stmt = mysqli_prepare($this->con, $sql); mysqli_stmt_bind_param($stmt, "i", $id); // "i"表示整数类型 mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); return mysqli_fetch_assoc($result); }
内容的提问来源于stack exchange,提问作者M'Baku
相关产品推荐
相关产品推荐

