繁体   English   中英

使用Mysql数据库的OOP PHP

[英]OOP PHP with Mysql Database

如果我们有这样的代码:

class Game {
    private $_id;
    private $_name;
    private $_url;

    public function __construct($_id,$_name,$_url){
        $this->_id = $_id;
        $this->_name = $_name;
        $this->_url = $_url;
    }
}

我们想简单地连接到我们的数据库以通过id获取游戏,我们在哪里放置'getByID'功能?

我们将它作为“静态函数”放在“游戏类”中,我们将它作为“公共函数”放在“数据库连接类”中,还是将该方法放在主索引中的'常规函数中? '作为'功能'?

我当前已选择'游戏类'中的'静态功能':

public static function getByID($id,$db){    
    $query = "SELECT * FROM game WHERE id = :id LIMIT 1";
    $prepare = array(":id"=>$id);
    $result = $db->Precute($query,$prepare);
    foreach($result as $r) return new Game($r['id'],$r['name'],$r['url']);
    return null;
}

(Precute是数据库类中的自定义函数,用于准备和执行查询)您将如何处理此问题?

在适当的OOP中,返回特定类的实例的DAL函数在该类中应该是静态的。 作为基本规则,与特定对象相关的所有功能都应该是该特定对象的一部分,如果在实例上调用则为实例方法,如果是创建或管理实例,则为静态方法('工厂模式')。

您的功能目前不是静态的,正确的用法是:

class Game
{
   ..other functions..

   public static function getById($id)
   {
      ..implementation, which can either access central storage or retrieve
        the object itself if concurrent edits are not an issue..
   }
}

其他地方:

$myGame = Game::getById(684);

你可能想看看Doctrine,而不是重新发明轮子。 即使您确实想要制作一个新的轮子,它的代码样本都遵循正确的OOP原则。

本答案采用另一种方法。 而不是从静态工厂获取对象。 此解决方案采用创建空白对象的方法,然后调用数据库方法以使对象成为实际行的实时表示。

首先是你问题的观察结果 -

Game类的对象/实例表示一排桌面game Game类本身可以作为“游戏”表的表示。

如果上述观察结果是正确的,并假设在类层次结构中有更多具有表示的表。 你应该有一个类来表示泛型'Table'

class Table {   //The class itself can be made abstract depending upon the exact implementation 
   protected $_tableName;
   protected $_connectionParams;
   protected $idAttribute = 'id';

   public function __construct($tableName, $connectionParams, $idAttribute){
       $this->_connectionParams = $connectionParams;
       $this->_tableName = $tableName;
       if(isset($idAttribute)) {
          $this->idAttribute = $idAttribute;
       }
   };

   private function _getConnection() {
      //return $db using $_connectionParams
   };

   public function getByID($id) {    
      $this->getByKeyVal($this->idAttribute, $id);
   };

   public function getByKeyVal($key, $val) {
      $query = "SELECT * FROM ". $this->_tableName ." WHERE `". $key ."` = :key LIMIT 1";
      $prepare = array(":key"=> $val);
      $result = $this->_getConnection()->Precute($query,$prepare);
      $this->processRow($result[0]);
   };

   //This needs to be overridden
   public function processRow($row) {
      return true;
   };
}

现在扩展Game Table的通用Table类

class Game extends Table {
   private $_id;
   private $_name;
   private $_url;
   public function __construct($defaults) {
      if(isset($defaults) {
         if(is_array($defaults)) {
            $this->processRow($defaults);
         } else {  
            $this->getByID($defaults);
         }
      } else {
         //Some default setup here if requried
      }
      $connectionParams = [];  //Prepare Connection Params here
      parent::__construct('game', $connectionParams);
   };

   //Override processRow
   public function processRow($row) {    
      if(isset($row['id']) {
         $this->_id = $row['id'];
      }
      $this->_name = $row['name'];
      $this->_url = $row['url'];
   };
}

以上是一个非常粗略的例子。 实际的类结构将取决于您的要求。 但一般的经验法则是将Class视为具体对象的蓝图。 与通用分类相关的所有方法都应该在自己的类中。

getConnection方法本身可以放入一个单独的DB连接类,并通过mixin模式或泛型类继承插入到表中。

像这样使用上面的设置

$game_new = new Game();  // for blank object  --- for a new row

$game_435 = new Game(435);    //row with 435 ID

$game_default = new Game(array(    //new row with defaults
  'name' => 'Some Name',
  'url' => 'Some Url'
));

你想要的是一个装满Game对象的“桶”。 当你想要一个游戏对象(代表数据库中的数据)时,你会要求你的“桶”给你。 让我举一个Doctrine2如何实现这个的例子: http//docs.doctrine-project.org/en/2.0.x/reference/working-with-objects.html

因此,您想要放置“getById”(或者我将“findById”)放在您的“桶”中。

// lets presume that the em is an instance of \Doctrine\ORM\EntityManager
// The entity manager does what the name says.
$id = 1234;
$game = $entity_manager->find('MyNamespace\Entity\Game', $id);
$game->setName('My first game!');
// We now tell the em to prepare the object for pushing it back to the "bucket" or database
$entity_manager->persist($game);
// Now we tell the em to actually save stuff
$entity_manager->flush();

这应该会告诉您如何使用它。 对象遵循单一责任原则 您不要求对象检索自己。 你要求“桶”检索一个对象。

http://en.wikipedia.org/wiki/Single_responsibility_principle

如果我告诉你有更多美丽的方式把东西放在他们的位置怎么办? 一个非常简单的案例可能包含3个基本组件:

  1. Db框架 - 处理数据访问。
  2. 表repsotor类 - 知道如何将类映射到表,如何从表数据创建类以及如何从表类创建数据。
  3. 包含实际类的模型或业务层。

为了更好地理解,您可以设想数据库对象映射器框架。 该框架可能非常复杂,但我们可以用几行来证明它的基本概念是如何工作的。

所以'框架':

<?php

//This class is for making link for db framework
class link
{
    public $link;
    public function __construct ($hostname, $database, $gamename, $password)
    {
        $this->link = new \PDO ('mysql:host='.$hostname.';dbname='.$database, $gamename, $password);
        $this->link->query('use '.$database);
    }
    public function fetch ($query)
    {
        $result = $this->link->query($query)->fetch();
    }
    public function query ($query)
    {
        return $this->link->query($query);
    }
    public function error ()
    {
        return $this->link->errorInfo();
    }
}

//This class collects table repositories and connections
class database
{
    public $link;
    public $tables = array ();
    public function __construct ($link)
    {
        $this->link = $link;
        table::$database = $this;
    }
}

//This is basic table repositor class
class table
{
    public static $database;
}

?>

现在我们有了db框架,让我们制作一些知道如何保存/加载/删除游戏的表格存储库:

class games extends table
{
    public function create ($row)
    {
        $return = new game ();
        $return->id = $row[0];
        $return->name = $row[1];
        var_export($row);
        return $return;
    }
    public function load ($id=null)
    {
        if ($id==null)
        {
            $result = self::$database->link->fetch("select * from games");
            if ($result)
            {
                $return = array();
                foreach ($result as $row)
                {
                    $return[$row[0]] = $this->create($row);
                }
                return $return;
            }
        }
        else
        {
            $result = self::$database->link->fetch("select * from games where id='".$id."'");
            if ($result)
            {
                return $this->create(reset($result));
            }
            else
            {
                echo ("no result");
            }
        }
    }
    public function save ($game)
    {
        if (is_array($save))
        {
            foreach ($save as $item) $this->save ($item);
        }
        if ($game->id==null)
        {
            return self::$database->link->query("insert into games set
                                                 name='".$game->name."'");
        }
        else
        {
            return self::$database->link->query("update games set name='".$game->name."'
                                                 where id='".$game->id."'");
        }
    }
    public function delete ($game)
    {
        self::$database->link->query ("delete from games where id='".$game->id."'");
    }
}

现在我们可以制作我们的模型,在这种情况下将包含实际的游戏类。

class game
{
    public $id;
    public $name;
    public function __construct ($name=null)
    {
        $this->name = $name;
    }
}

而实际使用它:

$database = new database (new link('127.0.0.1', 'system_db', 'root', '1234'));
$database->tables['games'] = new games();

if (!$database->tables['games']->save (new game('Admin')))
{
    var_export($database->link->error());
}

var_export($database->tables['games']->load(2));

目前,我喜欢这种模式,以便在我的项目中使用db。 使用它我可以实现我的实际业务对象(在这种情况下类游戏)将不知道它们的保存位置和方式。 这使我能够独立于实际存储并专注于项目逻辑。

还有一个轻量级框架,所谓的db.php( http://dbphp.net ),它甚至让我能够避免编写表存储库,甚至创建/修改我的业务类所需的表,但使用几乎相同我在这里描述的概念。

暂无
暂无

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

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