简体   繁体   English

PDO和PHP OOP代码建议

[英]PDO and PHP OOP Code Advice

I am very new to PHP Object Orientated Programming so was wondering if I could get some good advice on a database object I created. 我对PHP面向对象编程非常陌生,因此想知道是否可以对我创建的数据库对象获得一些好的建议。

I call the class db and include my class into every page load and initiate the database object using $db = new db . 我调用类db,并将我的类包含到每个页面加载中,并using $db = new db初始化数据库对象。 I then call the method inside this for each action I may need (building a menu from the database, getting login information etc.) with different parameters depending on what it is i want to do. 然后,针对每个我可能需要执行的操作(从数据库构建菜单,获取登录信息等),使用不同的参数调用此方法中的方法,具体取决于我要执行的操作。

It takes its first parameter as the query with the ? 它使用第一个参数作为带有?的查询。 symbol as replacements for values I want to bind, the second parameter is the values to bind to it in an array that is then looped through inside the prepared_statement method and the third parameter is the type ( FETCH_ARRAY returns an array of a SELECT statements rows, NUM_ROWS returns the amount of rows affected and INSERT returns the last inserted ID). 符号来代替我要绑定的值,第二个参数是要绑定到数组中的值,然后在prepare_statement方法内部循环遍历,第三个参数是类型(FETCH_ARRAY返回SELECT语句行的数组, NUM_ROWS返回受影响的行数,而INSERT返回最后插入的ID)。

An example of how I would call this function is below: 下面是我如何调用此函数的示例:

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

The second and third parameters are optional for if there are no parameters to be bound or no return is needed. 如果没有要绑定的参数或不需要返回,则第二个和第三个参数是可选的。

As I am new to OOP I am finding it hard to get my head around exactly when to use correctly and what are public, private, static functions/variables and design patterns (Singleton etc.). 由于我是OOP的新手,所以我很难准确地知道何时正确使用什么以及公共,私有,静态函数/变量和设计模式(Singleton等)。

I've read many tutorials to get as far as I hav but I feel now I need to take it here to get further answers or advice on where to go next with OOP and with this class I've built. 我已经阅读了许多教程,以达到我的最高水平,但是我现在觉得我需要在这里获得更多的答案或建议,以进一步了解OOP和我建立的此类课程。

It works as it is which for me is a good starting place except for any error handling which I will add in next but I want to make sure I am not making any obvious design errors here. 它的工作原理对我来说是一个很好的起点,除了我将在接下来添加的任何错误处理之外,但我想确保在这里没有犯任何明显的设计错误。

The code for the class is below: 该类的代码如下:

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; }

}

Your code is a bit outdated. 您的代码有些过时了。 You should use one of the visibility keywords instead of var to declare your properties. 您应该使用可见性关键字之一而不是var来声明您的属性。 In this case you probably want to use protected so that it cant be modified from outside the class but so that any future sub classes can modify it internally. 在这种情况下,您可能希望使用protected以便不能从类外部对其进行修改,但是任何以后的子类都可以在内部对其进行修改。 Youll also probably want to add a getter in-case you need to work with PDO directly (which you will - see my final statements below my class example). 在需要直接使用PDO的情况下,您可能还希望添加一个吸气剂(您将在下面的类示例中看到我的最终声明)。

Its bad to hard code you PDO connection information in the class. 对您在类中的PDO连接信息进行硬编码很不好。 You should pass these in as parameters same as you would if using PDO directly. 您应该像直接使用PDO一样将它们作为参数传递。 I would also add the ability to pass in a pre-configured PDO instance as well. 我还将添加传递预配置PDO实例的功能。

While not required, its a good idea to conform to PSR-0 through PSR-2 ; 虽然不是必需的,但通过PSR-2符合PSR-0是一个好主意; Sepcifically in your case im speaking about Class and method naming which should both be camelCase and the first char of the class should be capital. 在您的情况下,我直接谈论的是有关类和方法的命名,它们都应为camelCase,而该类的第一个字符应为大写。 Related to this your code formatting is also ugly particularly your block statements... If thats jsut an issue with copy and paste then ignore that comment. 与此相关的是,您的代码格式也特别丑陋,尤其是您的语句块...如果那是复制和粘贴的问题,那么请忽略该注释。

So overall i would refactor your code to look something like this: 所以总的来说,我将重构您的代码,使其看起来像这样:

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;  
    }

  }
}

Lastly, unless this is just for educational purposes I wouldnt do this. 最后,除非这只是出于教育目的,否则我不会这样做。 There are a ton of different queries that have varying part assemblies which arent considered here so at some point this is not going to support what you need it to do. 在这里,有很多不同的查询具有不同的零件装配,因此在任何时候都没有考虑过,因此在某些时候这将无法支持您所需的工作。 Instead i would use Doctrine DBAL, Zend_Db or something similar that is going to support greater query complexity through its API. 相反,我将使用Doctrine DBAL,Zend_Db或类似的东西,这些东西将通过其API支持更大的查询复杂性。 In short, dont reinvent the wheel. 简而言之,不要重新发明轮子。

I have developed something similar and it can helps you. 我已经开发出类似的东西,它可以为您提供帮助。

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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM