如何用PDO将数据库除指定列(如password)外的列映射到模型?
如何在纯PHP/SQL环境下实现类似Laravel模型隐藏属性的功能?
你现在遇到的问题其实很常见——不想每次修改数据库列都手动调整SQL的SELECT字段,同时要自动排除敏感字段(比如password)。下面给你几个实用的实现方向,完全贴合你的现有代码结构:
核心思路:复用模型属性定义自动生成查询字段
Laravel的模型隐藏属性本质是通过模型的属性配置来过滤查询结果,我们可以在纯PHP环境下用反射+模型静态配置来实现类似效果,不用再手动写死SELECT字段列表。
步骤1:给模型添加隐藏字段配置
先修改你的AccountModel,添加一个静态属性来定义需要自动排除的字段,同时保留原来的公共属性:
class AccountModel extends BaseModel { // 定义需要自动隐藏/排除的字段(和Laravel的$hidden逻辑一致) protected static $hidden = ['password']; public $id; public $userName; public $firstName; public $lastName; public $phoneNumber; public $userType; public $compliant; public $emailVerified; public $phoneVerified; // 即使数据库有password列,这里不用声明,或者声明了也会被自动排除 }
步骤2:封装字段自动生成逻辑(可复用)
为了让所有模型都能复用这个逻辑,建议把字段生成方法放到BaseModel里:
class BaseModel { // 默认无隐藏字段,子类可重写 protected static $hidden = []; /** * 获取需要查询的字段列表(自动排除隐藏字段) * @return array */ public static function getSelectableFields() { // 用反射获取当前模型的所有公共属性 $reflection = new ReflectionClass(static::class); $publicProperties = $reflection->getProperties(ReflectionProperty::IS_PUBLIC); // 提取属性名称(对应数据库字段名) $fieldNames = array_map(function($property) { return $property->getName(); }, $publicProperties); // 移除需要隐藏的字段,返回最终查询字段列表 return array_diff($fieldNames, static::$hidden); } }
步骤3:修改控制器查询逻辑
现在你可以在控制器里自动生成SELECT字段,不用再手动写死:
public function getUserByUsername($username) { $db = new Db(); // 自动获取需要查询的字段列表 $selectFields = AccountModel::getSelectableFields(); $selectClause = implode(', ', $selectFields); $query = $db->conn->prepare("SELECT $selectClause FROM apiAccount WHERE userName = :userName"); $query->bindParam(':userName', $username); if($query->execute()) { $db = null; $query->setFetchMode(PDO::FETCH_CLASS, 'AccountModel'); $result = $query->fetchAll(); if (isset($result[0])) { return $result[0]; } else { throw new APIException('Query could not be executed, user not found', 600, null, 'User does not exist'); } } else { $db = null; throw new APIException('Query could not be executed', 600, null, 'Dodgy SQL'); } }
方案优势
- 减少维护成本:新增数据库列时,只要在
AccountModel里添加对应的公共属性,就会自动被包含到查询中,不用修改SQL - 灵活控制敏感字段:只要在
$hidden数组里添加字段名,就能自动排除,比如以后要加其他敏感字段(如api_token),直接改模型配置即可 - 复用性强:把逻辑封装到
BaseModel后,其他模型也能直接使用这个功能
备选方案(不用反射)
如果不想用反射,也可以在模型里手动定义$visible属性来列出需要查询的字段,但这种方式需要手动维护字段列表,不如反射方案灵活:
class AccountModel extends BaseModel { protected static $visible = ['id', 'userName', 'firstName', 'lastName', 'phoneNumber', 'userType', 'compliant', 'emailVerified', 'phoneVerified']; // ... 其他属性 }
然后在getSelectableFields方法里直接返回static::$visible即可。
内容的提问来源于stack exchange,提问作者Varin
相关产品推荐
相关产品推荐

