2017-07-30 2 views
0
と反対

だから私は、の線に沿ってデータベースに同じ名前の列の値との性質を満たす、新しいオブジェクトを作るためにPDO :: FETCH_CLASS使用しました:PDO :: FETCH_CLASS

$db = Connection::get(); 
$sql = $db->prepare("SELECT * FROM table WHERE id = :id"); 
$sql->bindParam(":id", "1"); 
$sql->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'table'); 
$sql->execute(); 
$newobj = $sql->fetch(); 

bindParam()の全負荷と長いSQLクエリの入力を節約するために、オブジェクトのプロパティをテーブルの対応する列に挿入するには反対ですか?

多くのお礼ありがとうございます

+0

はい、 'execute()'メソッドでは、 'bindParam()'を使う代わりに配列を渡すことができます。 –

答えて

1

これは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; 
} 

(彼らはもちろん存在すると仮定した場合)、このような文字列を使用してプロパティやメソッドのコールにアクセスするために完全に罰金ですです便利なデータにアクセスしてください。

+0

本当に包括的な答え、歓声。反射は$ reflect = new ReflectionClass( "Staff")を使って本当に必要なものでした。 $ props = $ reflect-> getProperties();名前を取得するために$ propsをループします。どうもありがとう。 – Zero3X

+0

確かに、私は使うことができてうれしいです。 – ArtisticPhoenix

+0

私は 'new ReflectionClass(__CLASS __);'や 'new ReflectionClass(get_called_class());や' new ReflectionClass($ this);を使うこともできます。次に、クラスの名前を変更したりコードをコピーしたりする場合は、コードを変更する必要はありません。コードがクラス外になければ、 'new ReflectionClass(get_class($ obj));や' new ReflectionClass($ obj :: class); 'を使うこともできます。 – ArtisticPhoenix

0

私はこのようなことをしたいと思います。私はきちんと私に知らせてくださいあなたの質問を理解していない場合、これは、この上であなたに良いアイデアを与えるかもしれ(The only proper) PDO tutorial

$arr = [1,2,3]; 
$in = str_repeat('?,', count($arr) - 1) . '?'; 
$sql = "SELECT * FROM table WHERE foo=? AND column IN ($in) AND bar=? AND baz=?"; 
$stm = $db->prepare($sql); 
$params = array_merge([$foo], $arr, [$bar, $baz]); 
$stm->execute($params); 
$data = $stm->fetchAll(); 

を参照してください。

関連する問題