データベース操作にPDOを使用する場合、 pdostatement :: fetchObjectは非常に便利な方法であり、クエリ結果のデータの行をオブジェクトに直接マッピングできます。ただし、デフォルトでは、データベースがアンダースコアまたは異なるスタイルで名前を付けてフィールドを返す場合、 FetchObjectを直接使用すると、これらのフィールドをオブジェクトのプロパティに正しくマッピングできない場合があります。この記事では、この状況を優雅に処理する方法を詳細に説明します。
データベーステーブルユーザーが次のフィールドを持っているとします。
id
user_name
電子メールアドレス
通常、これを照会できます。
<?php
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'root', 'password');
$stmt = $pdo->query('SELECT id, user_name, email_address FROM users WHERE id = 1');
$user = $stmt->fetchObject();
echo $user->id; // 通常の出力
echo $user->user_name; // 通常の出力
echo $user->email_address; // 通常の出力
?>
ここではすべてが滑らかに見えます。ただし、エンティティクラス(ユーザーなど)がユーザー名やemailAddressなどのキャメルネーミングを使用している場合、 fetchObject( 'user')を直接使用しても、値は正しく割り当てられません。
FetchObjectは、デフォルトでデータベースによって返された列名に従ってオブジェクト属性に直接割り当てられるためです。データベース内のフィールドは下線( user_name )であり、オブジェクトはラクダ(ユーザー名)であり、当然対応していません。
たとえば、次のユーザークラス:
<?php
class User {
public int $id;
public string $userName;
public string $emailAddress;
}
?>
$ stmt-> fetchObject( 'user')を直接使用し、ユーザー名とemailAddressは値を取得できません。
最も単純で最も粗い方法は、SQLをクエリするときにオブジェクト属性名に一致するエイリアスをフィールドに与えることです。
<?php
$stmt = $pdo->query('
SELECT
id,
user_name AS userName,
email_address AS emailAddress
FROM users
WHERE id = 1
');
$user = $stmt->fetchObject('User');
echo $user->userName; // 正しい出力
echo $user->emailAddress; // 正しい出力
?>
この方法は、エンティティクラスを変更することなく、シンプルで直接的です。ただし、多くのクエリフィールドと複雑なテーブルがある場合、維持するのは困難です。
SQLのフィールド名を動かないようにしたい場合は、手動で配列を取り出してオブジェクトに割り当てることができます。
<?php
$stmt = $pdo->query('SELECT id, user_name, email_address FROM users WHERE id = 1');
$data = $stmt->fetch(PDO::FETCH_ASSOC);
$user = new User();
$user->id = $data['id'];
$user->userName = $data['user_name'];
$user->emailAddress = $data['email_address'];
echo $user->userName; // 正しい出力
?>
これは柔軟ですが、書くのは面倒です。毎回値を手動で割り当てる必要がありますが、これは十分にエレガントではありません。
より自動化したい場合は、データベースフィールドを自動的にCamel名に変換する小さな関数を記述し、値をオブジェクトに割り当てることができます。
<?php
function snakeToCamel(string $string): string {
return lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $string))));
}
function mapToEntity(array $data, string $className) {
$object = new $className();
foreach ($data as $key => $value) {
$property = snakeToCamel($key);
if (property_exists($object, $property)) {
$object->$property = $value;
}
}
return $object;
}
// 使用の例
$stmt = $pdo->query('SELECT id, user_name, email_address FROM users WHERE id = 1');
$data = $stmt->fetch(PDO::FETCH_ASSOC);
$user = mapToEntity($data, 'User');
echo $user->userName; // 正しい出力
?>
このようにして、コンバージョンロジックを一度書き込む必要があり、その後のすべてのクエリを自動的に処理できます。
FetchObjectは、シンプルで高速なデータ収集に適しています。複雑なロジックが必要な場合は、ORMフレームワーク(Laravelの雄弁、Symfonyの教義など)を使用することをお勧めします。
エンティティクラスの属性が公開されていることを確認してください。そうしないと、 FetchObjectを直接割り当てることはできません。
属性を保護する必要がある場合は、課題を処理するために、構築方法または魔法の方法__set()と協力する必要があります。
pdostatement :: FetchObjectは便利ですが慎重な機能です。フィールドネーミングスタイルが同期されていない場合は、SQLでエイリアスを使用するか、独自のマッピング方法を作成して、コードを清潔で堅牢に保つことができるようにすることをお勧めします。中型および大規模なプロジェクトの場合、成熟したORMライブラリを直接使用してエンティティマッピングを管理してエラーのリスクを減らすこともお勧めします。
PDO、データベースの最適化、またはエンティティマッピングに関するより高度なヒントをご覧になりたい場合は、テクノロジーブログhttps://gitbox.net/blogをご覧ください。