如何取得PDO物件並設定屬性? (代碼詳解)

藏色散人
發布: 2023-04-05 15:56:02
原創
2791 人瀏覽過

與任何其他資料庫擴充一樣,PDO可以直接從所選資料建立現有類別的實例。但是,與其他擴充不同的是,PDO為強大而靈活的物件操作提供了許多特性。

如何取得PDO物件並設定屬性? (代碼詳解)

取得單一物件

#要從查詢結果建立單一對象,有兩種方法。

1.使用熟悉的fetch()方法:

class User {};
$stmt = $pdo->query('SELECT name FROM users LIMIT 1');
$stmt->setFetchMode(PDO::FETCH_CLASS, 'User');
$user = $stmt->fetch();
登入後複製

2.專用的fetchObject()方法:

class User {};
$user = $pdo->query('SELECT name FROM users LIMIT 1')->fetchObject('User');
登入後複製

雖然這兩個程式碼段都將為你提供相同的User類別實例,

/* object(User)#3 (1) {
  ["name"] => string(4) "John"
} */
登入後複製

後一種方法看起來絕對更簡潔。此外,如果使用了fetch()方法,但是沒有使用這樣的名稱定義類,則將靜默傳回一個數組,而使用fetchObject()將拋出一個適當的錯誤。

取得物件陣列

當然,上面描述的兩種方法都可以與一個熟悉的while語句一起使用,從資料庫中取得結果行。

使用一個方便的fetchAll()方法一次取得物件陣列中所有傳回的記錄:

class User {};
$users = $pdo->query('SELECT name FROM users')->fetchAll(PDO::FETCH_CLASS, 'User');
登入後複製

將給你一個數組,由一個User類別的物件組成,返回資料填充屬性:

/* array(2) {
  [0]=> object(User)#3 (1) {
    ["name"] => string(4) "John"
  }
  [1]=> object(User)#4 (1) {
    ["name"]=> string(4) "Mike"
  }
} */
登入後複製

注意,你可以將此模式與PDO::FETCH_UNIQUEPDO::FETCH_GROUP組合使用,以獲得由唯一欄位索引的結果數組,或分別使用非唯一欄位對結果進行分組。

例如,下面的程式碼將傳回一個數組,其中記錄id將用作數組索引而不是連續數字。

class User {};
$stmt  = $pdo->query('SELECT id, id, name, car FROM users');
$users = ->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_UNIQUE, 'User');
登入後複製

指派類別屬性

無論選擇哪一種方法,查詢傳回的所有欄位都會依照下列規則指派給對應的類別屬性:

1.如果有一個類別屬性,它的名稱與列名相同,則將為該屬性分配列值

2.如果沒有這樣的屬性,那麼將呼叫一個魔術方法__set()

3.如果沒有為該類別定義__set()方法,那麼將建立一個公共屬性並為其指派一個列值。

例如,這段程式碼

class User
{
    public $name;
}
$user = $pdo->query('SELECT * FROM users LIMIT 1')->fetchObject('User');
登入後複製

將給你一個對象,所有屬性自動分配,無論它們是否存在於類別中:

/* object(User)#3 (4) {
  ["id"]   => string(3) "104"
  ["name"] => string(4) "John"
  ["sex"]  => string(4) "male"
  ["car"]  => string(6) "Toyota"
} */
登入後複製

從這一點可以看出,為了避免自動建立屬性,你可以使用魔術方法__set()過濾掉屬性。最簡單的過濾技巧就是一個空的__set()方法。使用它,只會設定現有的屬性:

class User
{
    private $name;
    public function __set($name, $value) {}
}
$user = $pdo->query('SELECT * FROM users LIMIT 1')->fetchObject('User');
/*
array(1) {
  [0]=> object(User)#3 (1) {
    ["name":"User":private]=> string(4) "John"
  }
} */
登入後複製

如上PDO還可以為私有屬性指派值。

將建構子參數傳遞給物件

#當然,對於新建立的對象,我們可能需要提供建構子參數。為此,fetchObject()fetchAll()方法都有一個專用的參數,你可以用它以陣列的形式傳遞建構函式參數。

假設我們有一個類別User,它有一個car屬性,可以透過提供的變數在建構函數中設定:

class User {
    public function __construct($car) {
        $this->car = $car;
    }
}
登入後複製

在取得記錄時,我們應該加入一個帶有建構函數參數的陣列:

$users = $pdo->query('SELECT name FROM users LIMIT 1')
             ->fetchAll(PDO::FETCH_CLASS, 'User', ['Caterpillar']);

$user = $pdo->query('SELECT name FROM users LIMIT 1')
            ->fetchObject('User',['Caterpillar']);
登入後複製
/* object(User)#3 (2) {
    ["name"] => string(4) "John"
    ["car"]  => string(11) "Caterpillar"
} */
登入後複製

可以看到,資料庫中的值被覆寫了,因為預設情況下PDO在呼叫建構子之前分配類別屬性。這可能是一個問題,但很容易解決:

在呼叫建構子後設定類別屬性

##mysql_fetch_object()註解:

如果你使用mysql_fetch_object並指定一個類別-屬性將在建構子執行之前設定。這通常不是問題,但是如果你的屬性是透過

__set()魔術方法設定的,那必須先執行建構函數邏輯,否則可能會導致一些主要問題。

可惜mysql是一個mysqli擴展,但我們使用的是PDO。因此,有一種方法可以告訴PDO在建構子執行之後分配屬性。為此,必須使用PDO::FETCH_PROPS_LATE常數。

使用fetchAll()會非常簡單,

class User {
    public function __construct($car) {
        $this->car = $car;
    }
}
$stmt  = $pdo->query('SELECT name, car FROM users LIMIT 1');
$users = $stmt->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'User', ['Caterpillar']);
登入後複製

在取得單一行時,我們需要同時呼叫setFetchMode()和fetchObject(),這可能有點不方便。

class User {
    public function __construct($car) {
        $this->car = $car;
    }
}
$stmt = $pdo->query('SELECT name, car FROM users LIMIT 1');
$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'User');
$user = $stmt->fetchObject('User', ['Caterpillar']);
/*
object(User)#3 (2) {
  ["car"]  => string(6) "Toyota"
  ["name"] => string(4) "John"
} */
登入後複製

如上這段程式碼效率並不高,因為我們必須寫兩次類別名稱。

或者,我們可以使用fetch():

$stmt = $pdo->query('SELECT name, car FROM users LIMIT 1');
$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'User', ['Caterpillar']);
$user = $stmt->fetch();
登入後複製

但是,如上所述,如果一個類別恰好是未定義的,它將無法幫助我們處理錯誤訊息。

從資料庫中取得類別名稱

還有一個更有趣的標誌,它告訴PDO從第一列的值中取得類名。使用這個標誌,可以避免使用setFetchMode()和fetch():

$data = $pdo->query("SELECT 'User', name FROM users")
            ->fetch(PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE);
/*
object(User)#3 (1) {
  ["name"]=> string(4) "John"
} */
登入後複製

此外,如果可以從同一個查詢創建不同類別的對象,那麼這種模式將非常有用

class Male {};
class Female {};
$stmt = $pdo->query('SELECT sex, name FROM users');
$users = $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE);
/*
array(6) {
  [0]=> object(Male)#3 (1) {
    ["name"]=> string(4) "John"
  }
  [1]=> object(Male)#4 (1) {
    ["name"]=> string(4) "Mike"
  }
  [2]=> object(Female)#5 (1) {
    ["name"]=> string(4) "Mary"
  }
  [3]=> object(Female)#6 (1) {
    ["name"]=> string(5) "Kathy"
  }
}*/
登入後複製

然而,當使用這種模式時,似乎不可能在類別建構子中傳遞任何參數。

更新現有物件#

除了创建新对象,PDO还可以更新现有对象。只使用setFetchMode(),它将现有变量作为参数。显然,使用fetchAll()是无用的。

class User
{
    public $name;
    public $state;

    public function __construct()
    {
        $this->name = NULL;
    }
}
$user = new User;
$user->state = "up'n'running";
var_dump($user);

$stmt = $pdo->query('SELECT name FROM users LIMIT 1');
$stmt->setFetchMode(PDO::FETCH_INTO, $user);
$data = $stmt->fetch();
var_dump($data, $user);
/*
object(Foo)#2 (2) {
  ["name"]  => NULL
  ["state"] => string(12) "up'n'running"
}
object(Foo)#2 (2) {
  ["name"]  => string(4) "John"
  ["state"] => string(12) "up'n'running"
}
object(Foo)#2 (2) {
  ["name"]  => string(4) "John"
  ["state"] => string(12) "up'n'running"
} */
登入後複製

如上,fetch()调用返回的是相同的对象,这在我看来是多余的。还要注意,与PDO::FETCH_CLASS不同,这种模式不分配私有属性。

以上是如何取得PDO物件並設定屬性? (代碼詳解)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板