PDostatement :: FetchObjectは、データベース操作にPDOを使用する場合、非常に便利な機能です。クエリの結果をオブジェクトに直接カプセル化して、手動の割り当ての手間を減らすことができます。ただし、不適切に使用すると、問題を引き起こす可能性があり、プログラムのパフォーマンスの低下や論理の混乱が生じます。
この記事では、重複したデータオブジェクトの読み込みを避けるために、 FetchObjectを正しく効率的に使用する方法を教えてください。
PHPでは、 pdostatement :: fetchObjectメソッドは、データベースクエリの結果から1つの行をクラスのインスタンスにカプセル化できます。サンプルコードは次のとおりです。
<?php
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'pass');
$stmt = $pdo->query('SELECT id, name FROM users');
while ($user = $stmt->fetchObject()) {
echo $user->id . ': ' . $user->name . '<br>';
}
?>
デフォルトでは、 FetchObjectは標準クラス( STDCLASS )オブジェクトを返し、インスタンス化するクラス名を指定することもできます。
クエリの結果に重複したレコードがあるか、同じデータが複数のクエリに表示され、毎回fetchObjectを介してオブジェクトを直接インスタンス化する場合、同じデータが表示され、複数の異なるオブジェクトインスタンスが作成されます。
例えば:
$user1 = $stmt->fetchObject();
$user2 = $stmt->fetchObject();
// それでも user1 そして user2 の id 同じ,它们也是不同の对象
この複製のインスタンス化は、メモリを無駄にするだけでなく、特に大規模なプロジェクトや複雑なデータ関連のクエリで一貫性のないデータ状態に問題を引き起こす可能性があります。
FetchObjectを介してオブジェクトが生成されるたびに、同じIDを持つオブジェクトが既に存在するかどうかを確認します。それが存在する場合、それは再利用され、再現されません。
例:
<?php
class User {
public $id;
public $name;
}
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'pass');
$stmt = $pdo->query('SELECT id, name FROM users');
$users = []; // 用来缓存已经加载の对象
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$id = $row['id'];
if (!isset($users[$id])) {
$user = new User();
$user->id = $row['id'];
$user->name = $row['name'];
$users[$id] = $user;
}
// すでに存在する場合,再利用 $users[$id]
}
この手動処理により、同じデータが一度だけインスタンス化されるようにします。
FetchObjectを独自のクラスに渡し、クラスコンストラクターにIDチェックを実装することにより、さらに自動化できます。
例えば:
<?php
class User {
private static $instances = [];
public $id;
public $name;
public function __construct() {
// 外部直接を禁止します new,使用 create 方法
}
public static function create($row) {
if (isset(self::$instances[$row['id']])) {
return self::$instances[$row['id']];
}
$obj = new self();
$obj->id = $row['id'];
$obj->name = $row['name'];
self::$instances[$row['id']] = $obj;
return $obj;
}
}
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'pass');
$stmt = $pdo->query('SELECT id, name FROM users');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$user = User::create($row);
}
?>
FetchObject自体は、怠zyな人々がオブジェクトをすばやく構築するために作成されていますが、プロジェクトにオブジェクトライフサイクルの高性能と統一された管理が必要な場合、少し制御する価値があります。
SQLクエリが十分に記述されていないため、複製データが表示される場合があります。たとえば、結合を行うときに正確に推定されない場合、同じメインレコードが複数回表示されます。
正しい方法は、SQLで個別のグループまたはサブクエリを使用して、返されたデータを制御することです。
例えば:
SELECT DISTINCT users.id, users.name
FROM users
LEFT JOIN orders ON orders.user_id = users.id
これにより、データのソースでの重複レコードの生成を減らし、問題を根本的に解決できます。
pdostatement :: fetchObjectを使用するのは便利ですが、オブジェクトの独自性に注意を払う必要があります。総括する:
大規模なプロジェクトの場合、オブジェクトキャッシュまたはオブジェクトプーリングモードに協力することをお勧めします。
小規模プロジェクトの場合、SQLを合理的に最適化すると、ほとんどの重複した負荷の問題を回避できます。
より厳格なオブジェクト管理が必要な場合は、 FetchObjectプロセスを手動でカプセル化することを検討できます。
PDOスキルについて詳しく知りたい場合、またはPHPデータアクセスレイヤーの標準セットが必要な場合は、詳細なケースとプラクティスについてはhttps://gitbox.net/php-tutorialsにアクセスすることをお勧めします。