2013-03-23 108 views
2

我很新的PHP面向对象编程,以便在想,如果我能我创建了一个数据库对象上得到一些好的建议。PDO和PHP的OOP代码意见

我打电话给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,我发现很难让我的头周围什么时候正确地使用,什么是公共的,私人的,静态函数/变量和设计模式(辛格尔顿等)。

我已经阅读了很多教程,只要我有,但我觉得现在我需要在这里获得进一步的答案或建议下一步与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; } 

} 

回答

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

+0

非常感谢你的回应!我会花时间仔细阅读这些内容,并检查您发布的链接,如果我有任何问题,请告诉我们,但非常感谢您的反馈意见,这正是我一直在寻找的内容。 – 2013-03-23 01:31:11

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

感谢您发布您的代码,但我的问题的真正意义在于获得有关我的代码的正确/错误的建议,并为真正理解OOP提供进一步的建议/帮助。我试图让我的db类只使用单一方法,以便在编写项目时更容易记住结构,因为我用它作为最后一个不同类型的所有SQL语句(SELECT,INSERT,DELETE等)。参数。 – 2013-03-23 00:20:52