2

私は PHP オブジェクト指向プログラミングに非常に慣れていないので、作成したデータベース オブジェクトについて良いアドバイスが得られるかどうか疑問に思っていました。

クラスdbを呼び出し、すべてのページ ロードにクラスを含め、データベース オブジェクトを開始しますusing $db = new db。次に、必要なアクション (データベースからメニューを作成する、ログイン情報を取得するなど) ごとに、目的に応じてさまざまなパラメーターを使用して、この内部のメソッドを呼び出します。

最初のパラメーターは、? を含むクエリとして受け取ります。バインドしたい値の置換としての記号、2 番目のパラメーターは、配列内でバインドする値であり、その後、prepared_statement メソッド内でループされ、3 番目のパラメーターは型です ( FETCH_ARRAY は、SELECT ステートメント行の配列を返します。 NUM_ROWS は影響を受けた行の量を返し、INSERT は最後に挿入された ID を返します)。

この関数を呼び出す方法の例を以下に示します。

$db->prepared_execute( "SELECT * FROM whatever WHERE ? = ? ", array( 'password', 'letmein' ), NUM_ROWS );

2 番目と 3 番目のパラメーターは、バインドするパラメーターがない場合、または戻り値が必要ない場合のオプションです。

私はOOPに慣れていないので、いつ正しく使用するか、パブリック、プライベート、静的関数/変数、およびデザインパターン(シングルトンなど)を正確に把握するのが難しいと感じています。

私はこれまでに多くのチュートリアルを読んできましたが、OOP と私が構築したこのクラスを使用して次にどこに行くべきかについて、さらなる回答やアドバイスを得るために、ここでそれを取る必要があると感じています。

次に追加するエラー処理を除いて、私にとっては良い出発点ですが、ここで明らかな設計エラーを犯していないことを確認したいと思います。

クラスのコードは次のとおりです。

class db {

var $pdo;

public function __construct() {

$this->pdo = new PDO('mysql:dbname=' . DB_NAME . ';host=' . DB_HOST . ';charset=utf8', DB_USER, DB_PASS);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

}

public function prepared_execute( $query, $bind_values = null, $type = null ) {

$preparedStatement = $this->pdo->prepare( $query );

if( $bind_values ) {

$i = 1;

foreach( $bind_values as $bind_value ) {

$preparedStatement->bindValue($i, $bind_value);

$i++;

} }

$preparedStatement->execute();

if(     $type == FETCH_ARRAY ) { return $preparedStatement->fetchAll();  }

elseif( $type == NUM_ROWS ) { return $preparedStatement->rowCount();     }

elseif( $type == INSERT   ) { return $this->pdo->lastInsertId();         }

else{   return true; }

}
4

2 に答える 2

1

あなたのコードは少し古くなっています。プロパティを宣言する代わりに、可視性キーワードの 1 つを使用する必要があります。varこの場合protected、クラスの外部からは変更できないが、将来のサブクラスが内部で変更できるようにするために使用することをお勧めします。また、PDO を直接操作する必要がある場合に備えて、おそらく getter を追加することもできます (これについては、クラスの例の下にある最終ステートメントを参照してください)。

クラスで PDO 接続情報をハードコーディングするのは悪いことです。PDO を直接使用する場合と同じように、これらをパラメーターとして渡す必要があります。また、事前構成された PDO インスタンスを渡す機能も追加します。

必須ではありませんが、PSR-0 から PSR-2に準拠することをお勧めします。特にあなたのケースでは、キャメルケースであり、クラスの最初の文字が大文字でなければならないクラスとメソッドの命名について話しています。これに関連して、コードのフォーマット、特にブロックステートメントも醜いです...それがコピーアンドペーストの問題である場合は、そのコメントを無視してください。

したがって、全体として、コードを次のようにリファクタリングします。

class Db {

  protected $pdo;

  public function __construct($dsn, $user, $pass, $options = array()) {

    if($dsn instanceof PDO) {
      // support passing in a PDO instance directly
      $this->pdo = $dsn;

    } else  {

      if(is_array($dsn)) {
        // array format
        if(!empty($options)) {
          $dsn['options'] = $options;
        }

        $dsn = $this->buildDsn($options);
      } else {
        // string DSN but we need to append connection string options
        if(!empty($options)) {
          $dsn = $this->buildDsn(array('dsn' => $dsn, 'options' => $options));
        }
      }

      // otherwise just use the string dsn
      // ans create PDO

      $this->pdo = new PDO($dsn, $user, $pass);
    }

    // set PDO attributes
    $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }

  public function getConnection()
  {
    return $this->pdo;
  }

  protected function buildDsn($options) {

    if($isDbParts = isset($options['dbname'], $options['hostname']) || !($isDsn = isset($option['dsn']))) {
      throw new Exception('A dsn OR dbname and hostname are required');
    }

    if($isDsn === true) {
      $dsn = $options['dsn'];
    } else if {
      $format = '%s:dbname=%s;host=%s';
      $driver = isset($options['dbtype']) ? $options['dbtype'] : 'mysql';
      $dsn = sprintf($format, $options['dbtype'], $options['dbname'], $options['host']);
    }

    if(isset($options['options'])) {
      $opts = array();

      foreach($options['options'] as $name => $value) {
        $opts[] = $name . '=' . $value;
      }

      if(!empty($opts)) {
        $dsn .= ';' . implode(';', $opts);
      }
    }

    return $dsn; 
  }

  public function preparedExecute( $query, $bind_values = null, $type = null ) {

    $preparedStatement = $this->pdo->prepare( $query );

    if( $bind_values ) {

      $i = 1;

      foreach( $bind_values as $bind_value ) {

        $preparedStatement->bindValue($i, $bind_value);

        $i++;
      } 
    }

    $preparedStatement->execute();

    if( $type == FETCH_ARRAY ) { 
      return $preparedStatement->fetchAll();  
    }
    elseif( $type == NUM_ROWS ) { 
      return $preparedStatement->rowCount();     
    }
    elseif( $type == INSERT   ) { 
      return $this->pdo->lastInsertId();         
    }
    else {   
      return true;  
    }

  }
}

最後に、これが単なる教育目的でない限り、私はこれを行いません。ここでは考慮されていないさまざまなパーツ アセンブリを含むさまざまなクエリが大量にあるため、ある時点で、必要なことをサポートできなくなります。代わりに、Doctrine DBAL、Zend_Db、または API を介してより複雑なクエリをサポートする同様のものを使用します。要するに、車輪を再発明しないでください。

于 2013-03-23T00:55:08.337 に答える