[英]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個基本組件:
為了更好地理解,您可以設想數據庫對象映射器框架。 該框架可能非常復雜,但我們可以用幾行來證明它的基本概念是如何工作的。
所以'框架':
<?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.