PDO和PHP OOP代码建议

时间:2013-03-23 00:11:06

标签: php oop class methods pdo

我是PHP面向对象编程的新手,所以想知道我是否可以对我创建的数据库对象有一些好的建议。

我调用类 db 并将我的类包含到每个页面加载中并启动数据库对象using $db = new db。然后我根据我想要做的事情,为我可能需要的每个动作调用方法(从数据库构建菜单,获取登录信息等),具有不同的参数。

它的第一个参数作为查询? symbol作为我要绑定的值的替换,第二个参数是在数组中绑定到它的值,然后在prepared_statement方法内循环,第三个参数是类型(FETCH_ARRAY返回SELECT语句行的数组, NUM_ROWS返回受影响的行数,INSERT返回最后插入的ID。)

我将如何调用此函数的示例如下:

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

如果没有要绑定的参数或者不需要返回,则第二个和第三个参数是可选的。

由于我是OOP的新手,我发现很难确切地知道何时正确使用以及什么是公共,私有,静态函数/变量和设计模式(Singleton等)。

我已经阅读了很多教程,但是我觉得现在我需要把它带到这里以获得有关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; }

}

2 个答案:

答案 0 :(得分:1)

您的代码有点过时了。您应该使用visibility keywords之一而不是var来声明您的属性。在这种情况下,您可能希望使用protected,以便它不能从类外部进行修改,但是以后任何子类都可以在内部修改它。您可能还想添加一个getter,以便您需要直接使用PDO(您将 - 在我的类示例下面看到我的最终陈述)。

在类中对您的PDO连接信息进行硬编码很难。您应该将这些参数作为与直接使用PDO时相同的参数传递。我还要添加传递预先配置的PDO实例的功能。

虽然不是必需的,但最好遵守PSR-0 through PSR-2;最后在你的情况下我说的是类和方法命名,它们都应该是camelCase,并且该类的第一个字符应该是大写。与此相关的是你的代码格式也很丑陋,特别是你的块语句...如果那就是复制和粘贴的问题,那么就忽略那个评论。

总的来说,我会重构你的代码看起来像这样:

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支持更高的查询复杂性。简而言之,不要重新发明轮子。

答案 1 :(得分:0)

我已经开发出类似的东西,它可以帮助你。

public function select($sql, $array = array(), $fetchMode = PDO::FETCH_ASSOC){      
    $stmt = $this->prepare($sql);

    foreach ($array as $key => $value){
        $stmt->bindValue("$key", $value);
    }

    $stmt->execute();
    return $stmt->fetchAll();
}

public function insert($table, $data){
    ksort($data);

    $fieldNames = implode('`,`', array_keys($data));
    $fieldValues = ':' .implode(', :', array_keys($data));

    $sql = "INSERT INTO $table (`$fieldNames`) VALUES ($fieldValues)";

    $stmt = $this->prepare($sql);

    foreach ($data as $key => $value){
        $stmt->bindValue(":$key", $value);
    }

    $stmt->execute();
}