首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 反射機制自動映射物件屬性到 SQL INSERT 實作

     編輯:PHP 相關知識

利用 ReflectionClass 動態讀取物件屬性,自動組裝 INSERT 語句,減少手寫 SQL 錯誤,適合簡易 ORM 或 ActiveRecord 基礎類別。

核心實作

<?php
class BaseModel {
    // 子類別需定義對應表名或由命名慣例推導
}

class Db {
    private PDO $pdo;

    public function insertModel(BaseModel $model, bool $returnId = false): int|bool {
        $class = get_class($model);
        $table = $this->tableName($class); // 如 user_model → users

        $refl = new ReflectionClass($class);
        $props = $refl->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED);
        // 略過靜態/主鍵等,視需求調整
        $fields = []; $placeholders = []; $values = [];

        foreach ($props as $prop) {
            $name = $prop->getName();
            if ($name === 'id') continue; // 假設自增主鍵
            $prop->setAccessible(true);
            $val = $prop->getValue($model);
            if ($val === null) continue; // 略過 null

            $fields[] = "`$name`";
            $placeholders[] = '?';
            $values[] = $val;
        }

        $sql = "INSERT INTO `$table` (" . implode(',', $fields) . ") VALUES (" . implode(',', $placeholders) . ")";
        $stmt = $this->pdo->prepare($sql);
        $ok = $stmt->execute($values);

        if ($returnId) return $ok ? (int)$this->pdo->lastInsertId() : 0;
        return $ok ? $stmt->rowCount() : false;
    }

    private function tableName(string $class): string {
        // 簡單慣例:UserModel → users
        return strtolower(preg_replace('/Model$/', '', $class)) . 's';
    }
}
?>

使用範例

<?php
class UserModel extends BaseModel {
    public $username;
    public $email;
    public $password_hash;
    public $created_at = 'NOW()'; // 特殊處理或由 DB 預設值
}

$user = new UserModel();
$user->username = 'john';
$user->email = 'john@example.com';
$user->password_hash = password_hash('secret', PASSWORD_DEFAULT);

$db = new Db($pdo);
$newId = $db->insertModel($user, true);
echo "新增 ID: $newId";
?>

優缺點與改進方向

優點缺點改進
零配置、自動同步屬性反射效能較慢 (可快取 ReflectionProperty 陣列)靜態快取 $refl->getProperties()
支援 protected/private (setAccessible)無法處理關聯、複雜型別、預設值邏輯引入屬性註解 (PHP 8 Attribute) 標註欄位對應
程式碼集中、易維護SQL 注入風險低 (參數化),但欄位名未轉義欄位名白名單或反引號包裹

進階:PHP 8 Attribute 版

<?php
#[\Attribute]
class Column {
    public function __construct(public string $name = '', public bool $primary = false, public bool $autoIncrement = false) {}
}

class UserModel {
    #[Column(name: 'id', primary: true, autoIncrement: true)]
    public int $id;
    #[Column(name: 'user_name')]
    public string $username;
    // ...
}
?>

搭配 ReflectionProperty::getAttributes(Column::class) 即可精準控制欄位對應、主鍵略過、型別轉換等。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved