簡體   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