これは1が1つの警告
- を行うには楽しかったが、これは、クラス内のすべての
public
のプロパティを取得し、クエリの一部としてそれらを使用しようとしています。あなたが本当に必要な場合は、それらをさらにフィルタリングすることができます。
私たちは、反射と呼ばれるものを使用しています。
これは二重の剣のようなものです。
一方で、これを基本クラスに入れて、すべてのオブジェクトで拡張することができます。そして、それらをうまく動作させることができます。後でテーブルにフィールドを追加する場合は、何も変更する必要はありませんが、それだけで動作します。
一方、文字列として記述するのではなく、これを処理するのに少し時間がかかります。このうちのいくつかは、protected static properties
内のクエリをキャッシュし、プロパティ自体をキャッシュすることで対処できます(値ではなく)。
抽象クラスを作成することから始めます。これは、この問題に対する非常に柔軟なアプローチであり、再利用のために自分自身を貸し出します。注:Insertメソッドだけをテストしましたので、他の部分にエラーがある場合は私を許してください。
abstract class BaseObject
{
public $id;
protected static $_DB;
public function getDB(\PDO $db){
if(!self::$_DB){
//@todo: connect to Database
}
return self::$_DB;
}
public function getId(){ return $this->id; }
public function setId($id){ $this->id = $id }
//returns the records id
public function save(){
//if there is no ID then we know it didn't come from the DB
if($this->id)
return $this->update();
else
return $this->insert();
}
// query format = 'INSERT INTO table (id, ...)VALUES(:id, ...)'
public function insert(){
$this->validate();
$db = $this->getDB(); //localize
$R = new \ReflectionObject($this);
$props = (array)$R->getProperties()[0];
$names = array_keys($props);
$sql = 'INSERT INTO '.$this->getTable().' ('.implode(',', $names).')VALUES(:'.implode(', :', $names).')';
$params = array_combine(
array_map(function($item){
return ':'.$item;
}, $names),
$props
);
$stmt = $db ->prepare($sql);
$stmt->execute($params);
$this->id = $db->lastInsertId(); //don't forget to update the id
return $this->id;
}
// query format = 'UPDATE table SET prop=:prop, ... WHERE id=:id'
public function Update(){
$this->validate();
$db = $this->getDB(); //localize
$R = new \ReflectionObject($this);
$props = (array)$R->getProperties()[0];
$names = array_keys($props);
$sql = 'UPATE '.$this->getTable().' SET ';
$set = [];
$params = [];
foreach($props as $name=>$value){
$params[':'.$name] = $value;
if($name == 'id') continue;
$set[] = "$name = :$name";
}
$sql .= implode(', ', $set).' WHERE id=:id'
$stmt = $db->prepare($sql);
$stmt->execute($params);
return $this->_id;
}
abstract public function getTable();
abstract public function vallidate();
}
次に、あなたの具体的なクラスであなただけの抽象メソッドを実装する必要があり、他のプロパティを追加し、それらに固有の
class Dude extends BaseObject
{
public $name;
public function getName(){ return $this->name ; }
public function setName($name){ $this->name = $name }
public function getTable(){
return 'dudes';
}
public function validate(){
if(empty($this->name)) throw new \Exception("Name cannot be empty");
//...etc.
}
}
あなたが知っておくべき、私はそのことを考えるように起こったことの一つ、クラスをロードするときに、PDOが発生すると、そのクラスのコンストラクタは呼び出されません。私はクラスをこのようにロードし、コンストラクタを強制的に呼び出す方法があるかもしれませんが、誤って呼び出されているかもしれません。しかし、それは言及する価値があるものです。
抽象クラスにはPDOインスタンスが必要なので、私はgetDB()
メソッドを追加しました。これは、すべてのクラスのDB接続をキャッシュする方法の簡単な例です(実際の接続部分を行うのは怠惰でした)。
個人的に私はDBのニーズに合わせてSingleton
私はちょうどこのself::$_DB = DB::getInstance();
のようなものを呼び出すだろうが、それは別の日の話です。
また、delete
メソッドを追加することをお勧めします。その結果、あなたのプログラマーのすべての人が話し続けるように、全体でCRUD
の経験を得ることができます。
私が考えることができるもう1つの大きな改善点は、静的なプロパティにこのようなものを保存できることです。基本的には、最初に実行した後にキャッシュします。そうすれば、クラスを複数回再処理(イントロスペクション)する必要がなくなります。
これはややこしいことですが、さらに問題を解決したいと思うでしょう。私があなたに与えることができる1つのヒントはself::$Var
ではなくstatic::$Var
をベースクラスに使用しているので、Late Static Binding
という名前を使用します。基本的には難しい部分です。なぜなら、全く別のものを持つ子孫クラスを持つことができるからです。私はこれが正しい用語かどうかは分かりませんが、スコープ解決の問題のようなものです。
しかし、私はあなたにこれらの最後のものを残します。この例では、正しいパス(または少なくとも私が知っているパス)を指摘して、可能なことについていくつかのアイデアを示します。
最後に一つは、それが、私はちょうど私があなたに別の方法を与えるためにそこにそれを出すだろうと思った
foreach($props as $name=>$value){
//for this we will say $name = 'id'
$method = "get".ucFirst($name); // 'getId'
$a = $this->$method(); // calls $this->getId()
$a = $this->$name; //access property $this->id;
}
(彼らはもちろん存在すると仮定した場合)、このような文字列を使用してプロパティやメソッドのコールにアクセスするために完全に罰金ですです便利なデータにアクセスしてください。
はい、 'execute()'メソッドでは、 'bindParam()'を使う代わりに配列を渡すことができます。 –