2

我对 PHP 面向对象编程非常陌生,所以想知道是否可以就我创建的数据库对象获得一些好的建议。

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

它将它的第一个参数作为带有 ? 的查询。符号作为我要绑定的值的替换,第二个参数是要在数组中绑定到它的值,然后在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; }

}
4

2 回答 2

1

你的代码有点过时了。您应该使用可见性关键字之一,而不是var声明您的属性。在这种情况下,您可能希望使用protected它以使其不能从类外部进行修改,但以便将来的任何子类都可以在内部对其进行修改。您可能还需要添加一个 getter,以防您需要直接使用 PDO(您将 - 请参阅我的类示例下方的最后陈述)。

在课堂上硬编码你的 PDO 连接信息是不好的。您应该将这些作为参数传递,就像直接使用 PDO 一样。我还将添加传递预配置 PDO 实例的功能。

虽然不是必需的,但符合PSR-0 到 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 支持更大的查询复杂性。简而言之,不要重新发明轮子。

于 2013-03-23T00:55:08.337 回答
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();
}
于 2013-03-23T00:16:46.770 回答