作者 主題: 可否幫忙看一下, 第一次接觸 class 這東西  (閱讀 4263 次)

0 會員 與 1 訪客 正在閱讀本文。

dwhtefr

  • 訪客
因為發覺程式開始有點鬆散, 所以學習寫了一個 class
主要是用來執行 sql 的 select, insert, update, delete 和 commit / rollback
但看起來好像怪怪的 =,=, 只是將 function 外面加了一個 class{}
可否指點一下我理解之下的格式有沒有錯  ???

所以程式碼如下
代碼: [選擇]
class db {

  // 標記 "開始交易"
  public function begin() {
  
    global $link;
  
    mysqli_query($link, "START TRANSACTION");
  }

  // 使用於 sql 查詢語法 Select (會產生 $result)
  public function query($sql, $msg, $file, $line) {
  
    global $link;
  
    if ( !($result = mysqli_query($link, $sql)) )
    {
     $error_msg[] = array($file, $line, $msg, $sql, mysqli_error($link));
     $this->error_exit($error_msg);
    }
    return $result;
  }

  // 使用於 sql 更新語法 Insert / Update / Delete (不會產生 $result)
  public function update($sql, $msg, $file, $line) {
  
    global $link, $error_msg;
  
    if ( !(mysqli_query($link, $sql)) )
    {
     $error_msg[] = array($file, $line, $msg, $sql, mysqli_error($link));
    }
    return;
  }

  // 標記 "完成交易" , 根據 $error_msg 而決定 commit 或 rollback
  public function commit() {
  
    global $link, $error_msg;

    if ($error_msg)
    {
      mysqli_query($link, "ROLLBACK");
      $this->error_exit($error_msg, 'ROLLBACK');
    }
    else
    {
      mysqli_query($link, "COMMIT");
    }
    return;
  }

  // 將交來的 $msg_arr 拆開, 印出每一個錯誤
  public function error_exit($msg_arr, $rollback_msg = '') {
  
    $errors = ($rollback_msg == 'ROLLBACK') ? '因在執行資料 Insert / Update / Delete 時出現下列錯誤, 所有資料已經 ROLLBACK<br><br><hr>' : '';

    $errors_arr = array();
    foreach($msg_arr as $val)
    {
      $errors_arr[] = sprintf('檔案: %s 行數: %d<br>錯誤描述: %s<br>SQL 語法: %s<br>MySql 錯誤訊息: %s', $val[0], $val[1], $val[2], $val[3], $val[4]);
    }
  
    $errors .= implode('<br><br>', $errors_arr);
    exit($errors);
  }
}

以下是用法
代碼: [選擇]
<?php
// 連線
if ( !($link = @mysqli_connect($dbhost$dbuser$dbpass$dbname)) ) 
{
die("連接或選擇資料庫失敗");
}

$error_msg = array(); // 這個變數是主要的關鍵
$db = new db();

// 使用方法: 一般的查詢
$sql "SELECT * FROM table";
$result $db->query($sql"無法找取資料表 ... 資料"__FILE____LINE__); // 如果有錯會自動印出格式化了的錯誤訊息

// 使用方法: 當要更新資料, 如 insert / update / delete
$db->begin(); // 標記 "開始交易"

$sql "DELETE FROM table WHERE id = $id";
$db->update($sql"無法刪除 ... 的資料"__FILE____LINE__); // update 不會即時印出錯誤訊息. 將這次的錯誤加進 $error_msg, 直到 commit 時作判斷, rollback 之後才印出全部錯誤訊息

$sql "INSERT INTO table (id, name) VALUES ($id$name)";
$db->update($sql"無法新增 ... 的資料"__FILE____LINE__);

$db->commit(); // 標記 "完成交易" , 根據 $error_msg 而決定 commit 或 rollback
?>


原本要執行 sql 查詢或更新時都要重複寫好幾行程式碼來判斷, 現在好像簡潔了一點, 只要記著這 4 行東西
$db->query($sql, "", __FILE__, __LINE__);
$db->begin();
$db->update($sql, "", __FILE__, __LINE__);
$db->commit();


想請問一下:
(1) class 裡是否一定要在第一個 method 建立 function __construct() {} ? 它的意義是執行一些預備工作?
(2) 我的 class 裡有好幾個 method 都要保留 $error_msg, 除了 global 之後還有沒有其他方案 ?


抱歉, 第一次接觸 class, 很多不太會, 請好心的大大指點一下
« 上次編輯: 2011-04-15 22:16 由 dwhtefr »

Yamaka

  • 俺是博士!
  • *****
  • 文章數: 4913
    • 檢視個人資料
    • http://www.ecmagic.com
想請問一下:
(1) class 裡是否一定要在第一個 method 建立 function __construct() {} ? 它的意義是執行一些預備工作?
(2) 我的 class 裡有好幾個 method 都要保留 $error_msg, 除了 global 之後還有沒有其他方案 ?

簡單來說
(1) __construct() 是建構子, 當你使用 new db() 時, 會自動跑這個函數
是物件最先執行的地方, 所以通常用來做一些初始化工作與參數處理
並沒有規定要放在最開頭

(2) 設一個 private 變數, 物件內所有method都可以存取這個變數, 例如:

class db {
  private $error_msg;
 ........
}

然後在 method 裡就可以用 $this->error_msg 來存取這個變數

詳細說明, 建議直接看 php 官網或是相關的文章或書籍

dwhtefr

  • 訪客
先感謝 Yamaka 的回覆

(1) 那裡應該明白了

(2) 如果如你所說將 $error_msg 定義為 屬性, public 或 private 或 protected $error_msg;
物件裡可以使用 $this->error_msg

但是在外面的 php 流程每呼叫一次, $this->error_msg 不就是會消失  ???

就像我最下面使用方法裡提到有 2 次 $db->update(.......)
第一次 $db->update(...) delete 時出現錯誤, 將錯誤訊息加進 $error_msg[], 但不要即時印出錯誤
第二次 $db->update(...) insert 時也出現錯誤, 將錯誤訊息加進 $error_msg[], 但不要即時印出錯誤
...
...
直到出現 $db->commit();
這時的 $error_msg[] 裡會有 2 筆錯誤記錄
所以我只能想到用 global 來保存 $error_msg, 不會因為執行一次就消失了
在我的情況下是否只能用 global ? 沒有其他替代方案?

Yamaka

  • 俺是博士!
  • *****
  • 文章數: 4913
    • 檢視個人資料
    • http://www.ecmagic.com
(2) 如果如你所說將 $error_msg 定義為 屬性, public 或 private 或 protected $error_msg;
物件裡可以使用 $this->error_msg

但是在外面的 php 流程每呼叫一次, $this->error_msg 不就是會消失  ???

就像我最下面使用方法裡提到有 2 次 $db->update(.......)
第一次 $db->update(...) delete 時出現錯誤, 將錯誤訊息加進 $error_msg[], 但不要即時印出錯誤
第二次 $db->update(...) insert 時也出現錯誤, 將錯誤訊息加進 $error_msg[], 但不要即時印出錯誤
...
...
直到出現 $db->commit();
這時的 $error_msg[] 裡會有 2 筆錯誤記錄
所以我只能想到用 global 來保存 $error_msg, 不會因為執行一次就消失了
在我的情況下是否只能用 global ? 沒有其他替代方案?

你有先試過了嗎?  ::)

代碼: [選擇]
<?php
class MyClass {
  private 
$mesg;

  public function 
__construct() {
    
$this->mesg = array();
    
$this->mesg[] = __FUNCTION__;
  }
  
  public function 
query() {
    
$this->mesg[] = __FUNCTION__;
  }
  
  public function 
update() {
    
$this->mesg[] = __FUNCTION__;
  }
  
  public function 
commit() {
    
$this->mesg[] = __FUNCTION__;
    
print_r($this->mesg);
  }
}

$obj = new MyClass();
$obj->query();
$obj->update();
$obj->update();
$obj->commit();
?>

result:

Array ( [ 0 ] => __construct [1] => query [2] => update [3] => update [4] => commit )

dwhtefr

  • 訪客
Yamaka 大大, 您這個答案真的是我意料之外  ;D

非常非常感恩謝謝, 那我的問題完全解決了  ;D

class 裡的變數如沒經外面參數呼叫修改, 在 class 裡面可以保存

dwhtefr

  • 訪客
 ;D 好開心, 最終版本

代碼: [選擇]
<?php
class db {

  private 
$error_msg = array();

  
// 標記 "開始交易"
  
public function begin() {
  
    global 
$link;
  
    
mysqli_query($link"START TRANSACTION");
  }

  
// 使用於 sql 查詢語法 Select (會產生 $result 或 出現錯誤會即時印出錯誤)
  
public function query($sql$msg$file$line) {
  
    global 
$link;
  
    if ( !(
$result mysqli_query($link$sql)) )
    {
    
$this->error_msg[] = array($file$line$msg$sqlmysqli_error($link));
    
$this->error_exit($this->error_msg);
    }
    return 
$result;
  }

  
// 使用於 sql 更新語法 Insert / Update / Delete (不會產生 $result 或 出現錯誤先記錄訊息, 不印出錯誤)
  
public function update($sql$msg$file$line) {
  
    global 
$link;
  
    if ( !(
mysqli_query($link$sql)) )
    {
    
$this->error_msg[] = array($file$line$msg$sqlmysqli_error($link));
    }
    return;
  }

  
// 標記 "完成交易" , 根據 $error_msg 而決定 commit 或 rollback
  
public function commit() {
  
    global 
$link;

    if (
$this->error_msg)
    {
      
// rollback 及 印出已經記錄了的所有錯誤
      
mysqli_query($link"ROLLBACK");
      
$this->error_exit($this->error_msg, &#39;ROLLBACK&#39;);
    
}
    else
    {
      
mysqli_query($link"COMMIT");
    }
    return;
  }

  
// 將交來的 $msg_arr 拆開, 印出每一個錯誤
  
public function error_exit($msg_arr$rollback_msg = &#39;&#39;) {
  
    
$errors = ($rollback_msg == &#39;ROLLBACK&#39;) ? &#39;因在執行資料 Insert / Update / Delete 時出現下列錯誤, 所有資料已經 ROLLBACK<br><br><hr>&#39; : &#39;&#39;;

    
$errors_arr = array();
    foreach(
$msg_arr as $val)
    {
      
$errors_arr[] = sprintf(&#39;檔案: %s 行數: %d<br>錯誤描述: %s<br>SQL 語法: %s<br>MySql 錯誤訊息: %s&#39;, $val[0], $val[1], $val[2], $val[3], $val[4]);
    
}
  
    
$errors .= implode(&#39;<br><br>&#39;, $errors_arr);
    
exit($errors);
  }
}
?>


使用方法:
代碼: [選擇]
<?php
// 連線
if ( !($link = @mysqli_connect($dbhost$dbuser$dbpass$dbname)) ) 
{
die("連接或選擇資料庫失敗");
}

$db = new db();

// 使用方法: 一般的查詢, 不同於 insert / update / delete, 不需要 rollback 資料, 所以有錯誤就直接印出格式化了的錯誤訊息
$sql "SELECT * FROM table";
$result $db->query($sql"無法找取資料表 ... 的資料"__FILE____LINE__);


// 使用方法: 當要更新資料時, 如 insert / update / delete, 當有錯誤時會先將訊息記錄下來
// 這方法必須要的 3 個步驟

// 步驟 1 -- 標記 "開始交易"
$db->begin();

// 步驟 2 -- 開始你的資料更新
$sql "DELETE FROM table WHERE id = $id";
$db->update($sql"無法刪除 ... 的資料"__FILE____LINE__);

$sql "INSERT INTO table (id, name) VALUES ($id$name)";
$db->update($sql"無法新增 ... 的資料"__FILE____LINE__);

...
...

// 步驟 3 -- 完成所有更新指令之後, 標記 "完成交易", 當有錯誤時會還原曾修改的資料, 然後印出錯誤訊息
$db->commit();

?>


現在 class 外面可以不設置 $error_msg 了, yeah, 感恩

jaceju

  • 憂鬱的高中生
  • ***
  • 文章數: 106
    • 檢視個人資料
要記住一個很重要的事,就是除了 Exception 外,不要在 class 裡使用 exit 或是 die ;讓物件的生命有始有終是很重要的。

dwhtefr

  • 訪客
要記住一個很重要的事,就是除了 Exception 外,不要在 class 裡使用 exit 或是 die ;讓物件的生命有始有終是很重要的。

這個有點深奧, 以我上面的例子來說, 在處理資料時得到一個完整性, 不要在處理資料運算時中途退出

當真的跑到程式碼遇到致命錯誤時, 轉用一個無害的退出方式  ???

就好像在物件裡改用 return 的方式, 在主程序來做判斷, 如果換成人類的語言來說, 就是 "你(指物件)要做的事已經完成, 其他的事等我來處理" ???

就我上面的簡單幾行程式碼而言, 其實是否做到無害的方式退出 ???

還是要買本書回來看一下好了  :o
« 上次編輯: 2011-04-19 00:01 由 dwhtefr »