OOPでOODとグッドプラクティスについて学び、いくつかの重要な概念に苦労していることに気づきました。実践として、以前は単一ファイルクラスであったカスタムPDOデータベース抽象化レイヤーを書き換えています> 2000行のコード。
I 学習済み クラスが「is an」関係にある場合は継承を使用し、「has a」関係がある場合は合成を使用する必要があります。 PHPのtraits
を回避することを前提に、構成は次のように実装できます(例 here から):
_<?php
class Head {
}
class Human {
private $head;
public function __construct(Head $head) {
$this->head = $head;
}
}
$bob = new Human(new Head);
_
良い。ただし、私の場合は、クラスBをAに合成しますが、Bのインスタンスは複数存在する可能性があります。正確には、メインのdatabase
クラス(A)が1つまたは複数のtable
クラス(B)。上記の例のtable
オブジェクトに似たhead
オブジェクトを注入することは、私が望むものではないかもしれません。後で、おそらくselectクラスまたはinsertクラスも存在する可能性があります。これは練習のためだけに行い、クラスのファイルサイズを小さく保つ方法を学びます。構築中にすべての依存関係をすべて注入して再利用する必要がありますか?または、メインのdatabase
クラス内でインスタンス化し、サブクラスへの接続を注入する必要があります。メインデータベースクラスは、PDOオブジェクトを '$ _connection'に保持します。
database
とtable
を構成する最良の方法は何ですか。私はこれらの戦略を考えることができます。
_<?php
class db extends PDO{
private $_connection;
public function __construct($dsn){
$this->_connection = new parent::__construct($dsn);
}
public function createTable($def){
$table = new Table(this->_connection, $def);
}
}
_
短所:
new
演算子は、一般的に理想的ではないと思われるメソッドに含まれています。すべてのインスタンスを注入する必要があります。createTable
メソッドを宣言する必要があります。これは私の基本クラスをスパムします。機能が増えると、基本クラスはどんどん大きくなります。そもそもそれを回避したかったのです。 Table->create()
のように、テーブルオブジェクトでcreate
を呼び出せるようにしたいのですが。_<?php
class db extends PDO{
private $_connection;
public $table;
public function __construct($dsn, $table){
$this->_connection = new parent::__construct($dsn);
$this->table = $table;
}
}
$db = new db($dsn, new $Table)
$db->table->create($def);
_
短所:
connection
を使用できません。私は、dbクラスとTableクラスが「is a」関係にあるとは思わないため、相互に継承すべきではありません。しかし、現在のところ、適切なコンポジション実装が不足しています。
免責事項
私は解決策を模索しましたが、これのためのベストプラクティスとなる可能性があるものについて助けが必要です。例(人間、頭)で投稿された構成は、データベースとテーブルの場合、ここでは正しく感じられません。役立つ回答が得られることを願っています。また、リンクや話題の言葉を歓迎します。今学んでいるだけで、次のレベルに進むのに苦労しているようです。
Table
オブジェクトがある理由、またはdb
クラスがPDO
を拡張する理由がわかりませんが、データベースアクセスへの適切なアプローチを説明しますPHPコンテキスト、これは私が多くの時間を費やしていて、非常に興味を持っている分野なので、.
PDOと準備済みステートメントを使用した基本的なDIアプローチ
PHPのPDO
/PDOStatement
コンテキストでのデータベースアクセスを検討する場合、実際にそれを要約すると、次のようになります。
ポイント1はデータベースアクセサーの責任であり、PDOの作成を伴います。これは「ある」関係です。
ポイント2と3は、データベースアクセサーのPDOによるデータベースアクセサーの責任でもあると私は主張します。この場合、データベースアクセサーはメディエーターまたはファサードとして機能します。
ポイント4は、データアクセスオブジェクト(DAO)の役割です。
データベースアクセサーは、次のようなインターフェイスを実装します。
_interface DatabaseAccessorInterface
{
public static function beginTransaction(): void;
public static function commitTransaction(): void;
public static function dropConnection(): void;
public static function getConnection(): PDO;
public static function isActiveTransaction(): bool;
public static function prepare($sql): PDOStatement;
public static function rollbackTransaction(): void;
}
_
...そしてデータアクセスオブジェクトの抽象実装は次のようになります。
_abstract class AbstractDAO
{
private $db;
public function __construct(DatabaseAccessorInterface $db)
{
$this->db = $db;
}
protected function db(): DatabaseAccessorInterface
{
return $this->db;
}
}
class UserDAO extends AbstractDAO
{
public function getAllUsers(): array
{
$sql = "SELECT * FROM user";
$stmt = $this->db()->prepare($sql);
$stmt->execute();
return $stmt->fetchAll();
}
public function getUserByUsername($username): array
{
$sql = "SELECT * FROM user WHERE username = :username";
$stmt = $this->db()->prepare($sql);
$parameters = [
':username' => $username
];
$stmt->execute($parameters);
return $stmt->fetch();
}
}
_
これは、問題に対する従来の「簡単な」アプローチであり、IMOの最良のアプローチではありませんが、PDOと準備されたステートメントの設計に取り掛かる場合の優れた出発点です。
このアプローチを強化する方法は次のとおりです。
Result
またはfetchAll()
の代わりにカスタムfetch
オブジェクトを返すため、rowCount
、errorCode
などの追加情報を取得できます、など.著者の考え
個人的には、データベースのコンテキストでのデータアクセスについて考えることは、今日の時代では非常に制限されていると思います。今日では、データベースは無数の選択肢の中の永続化の一形態にすぎません。 SQLデータベース、NoSQLデータベース、CSVファイル、リモートAPIなどに接続することができます。データベースへの接続とクエリから、リモートへのアクセスへとデータアクセスの考え方を広げた方がいいと思います。多くの形式を取ることができるデータストア。
このように見ると、さまざまな部分が機能していることがわかります。
Accessor
AccessorConfiguration
の構成情報を保持するAccessor
PersistenceStrategy
Calls
、SQLクエリ文字列に相当Responses
は、Calls
の実行に関する情報(たとえば、返される行/列の数、エラー情報など)を保持します。OperationRepository
の実行を担当し、Calls
を返すResponses
OperationCache
に対してResponses
を格納するCalls
この道を進むと、インターフェイスの言語が大幅に簡素化され、データベース固有の専門用語でコードを汚染することがなくなります。
_interface PersistenceStrategyInterface
{
/**
* Deletes a DataEntity from the persistence mechanism.
*
* @param DataEntityInterface $dataEntity
* @return ResponseInterface
*/
public function delete(DataEntityInterface $dataEntity);
/**
* Gets a DataEntity from the persistence mechanism.
*
* @param DataEntityInterface $dataEntity
* @return ResponseInterface|null
*/
public function get(DataEntityInterface $dataEntity);
/**
* Saves the DataEntity to the persistence mechanism.
*
* @param DataEntityInterface $dataEntity
* @return ResponseInterface
*/
public function save(DataEntityInterface $dataEntity);
}
interface OperationRepositoryInterface
{
/**
* Gets the Response from the OperationRepository.
*
* @param CallInterface $call The Call that generates the Response.
* @param AccessorInterface $accessor The Accessor that the Call is made against.
* @return ResponseInterface
*/
public function response(CallInterface $call, AccessorInterface $accessor);
}
_
免責事項:このコードは Circle314フレームワーク からのものです。これは現在開発中です