2015-11-06 77 views
1

之前,我問我的問題,我想確認一些事情是清楚的:PHP OOP代碼由於語法錯誤而失敗?

1)我讀了OOP(介紹,基礎知識,繼承性等官方PHP手冊)似乎IM誠實沒有得到什麼。進入它現在幾個小時,並修復了一些東西,然後出現新的錯誤。

2)我讀了錯誤信息Main :: __ construct()和Undefined variable:array缺少參數1。這意味着我的$ start變量是NULL。

3)我做的幾個搜索計算器要麼是對我明白什麼,因爲示例代碼事情是如此複雜(不爲首發的最好的事情)並不完全相關或很辛苦。

我的問題:爲什麼下面的代碼不工作?我真的很感激爲什麼它失敗了,我必須考慮。

class Main { 
    protected $config; 
    protected $start; 

     function __construct($arr) { 
      if(!isset($this -> start)) { 
       if ($arr['secure']){ 
        $this -> config = parse_ini_file('C:\xampp\htdocs\project\config.ini'); 
        $this -> start = mysqli_connect($this -> config['host'], $this -> config['username'], 
                $this -> config['password'], $this -> config['database']); 
       } 
       else { 
        $this -> start = mysqli_connect($arr['host'], $arr['username'], $arr['password'], $arr['database']); 
       } 
      } 
      if($this -> start == false) { 
       return mysqli_connect_error(); 
      } 
     } 
    } 

$Main = new Main($array = ["host" => '', "username" => '', "password" => '', "database" => '', 
          "errors" => false, "secure" => true]); 

    class Test extends Main { 
     public function sample() { 
      $query = "SELECT id, user, 
         FROM users"; 
      $result = mysqli_query($Main -> start , $query); 
      $row = mysqli_fetch_array($result); 
      echo $row['user']; 
     } 
    }  

    $x = new Test(); 

    $x -> sample(); 

回答

2

因此,這裏是上運行時會發生什麼:

$Main = new Main(...); 

OK,你可能會得到一個連接那裏,如果這些細節被填充,但在決定是否做了成功的連接,或者不是一個問題。請參閱下面的更多信息,但$Main現在需要注意。

$x = new Test(); 

Test擴展您Main類。 因此,您的類Test繼承了類Main的構造函數,該構造函數需要參數。該參數未提供,因此會生成警告。

爲了解決這個問題,使$arr可選的,如果你不總是會被傳遞:

function __construct($arr = array()) 

然後檢查是否存在通過對指標使用isset

if(isset($arr['secure'])) // ... 

快進,因爲您沒有提供$arr,您將無法成功連接到您的數據庫。根據mysqli::__construct()(其中mysqli_connect是別名),它將嘗試返回一個對象(「表示與MySQL服務器的連接」)。

現在,看看這些行:

$this -> start = mysqli_connect(...) 
// ... 
if ($this -> start == false) { 

You must check against the return's connect_error attribute (or mysqli_connect_error()) to verify if the connection worked or not.

由於下面的評論,你也應該檢查是否有虛假的分配,作爲mysqli_connect已經知道產生警告,即使它沒有在PHP文檔中顯示,也會返回false。

讓我們繼續。

$x -> sample(); 

Test::sample使用mysqli_query其預計數據庫連接,因爲它是第一個參數。您通過傳遞$Main->start來嘗試此操作。

不幸的是,$Main不在您的variable scope中,無法從該方法內部訪問。你需要參考的是$this->start

事實上,如果這是你實例化$Main的唯一原因,那麼你不需要那個時候。相反,請將連接詳細信息數組傳遞給new Test()

這裏有兩種解決方案:

  1. 通過對$x = new Test(); 實例傳遞你的數據庫連接的詳細信息,然後將連接到數據庫如預期,將能夠運行查詢。
  2. 單獨的類從類Main中進行測試,並通過類Test的構造函數傳遞類Main的實例。 可能是更好的選擇。如果您的測試是爲了您的查詢而不是擴展Main,請創建您的數據庫連接對象(new Main(..)),然後將其傳遞到new Test($Main)。在您的測試類,創建它接受主類作爲參數的構造函數:

    public function __construct(Main $main) 
    { 
        $this->db = $main; 
    } 
    

通過使$main$start屬性public,或通過創建getter功能允許訪問連接對象(如getConnection()),然後比在查詢中使用:

$result = mysqli_query($this->db->getConnection(), $query); 

有很多很多的方式,你可以接近你的情況下,它的下跌給你。 答案已經解決了最初的問題,但我想我也可以提供一些實施建議。

+0

這真的很詳細。我現在要讀這個。來自JS OOP有點困難,所以我非常感謝。 – Asperger

+0

對象可以是NULL,所以我可以說== NULL? – Asperger

+1

實際上,儘管文檔中說'mysqli_connect()'會返回一個對象,但實際上它可以拋出一個警告並返回false。試試這個:'var_dump(mysqli_connect('','','',''));' – Flosculus

0
$result = mysqli_query($Main -> start , $query); 

$result = mysqli_query($this -> start , $query); 

即至少除去語法錯誤。 $this是一個內省變量,它總是指當前的實例範圍。

+0

但後來它不使用來自新對象 – Asperger

+0

連接$ Main = new Main – Asperger

+0

'new Test()'是繼承的'Main'的實例,所以'Test'的實例可以訪問'Main'的受保護成員。如果它們意圖相同,則不需要將'Main'的實例注入到'Test'的實例中。 – Flosculus

0

您正在使用兩個不同的實例。

// This is one instance 
$Main = new Main([...]); 

// This is a different instance. 
$test = new Test(); 

擴展類並不意味着它從類的現有實例中獲取值。它只意味着它獲得相同的方法(和默認屬性)。

因此,您的類Test獲得與Main相同的構造函數,這意味着您需要將數組發送到Test以便能夠使用實例化它。在你的例子中,沒有理由直接實例化Main。

0

退房的評論如下

//I suggest to make this class abstract to make sure 
//php doesn't let you to instantiate it directly as you did before 

    abstract class Main { 

     protected $config; 
     protected $start; 

      function __construct($arr) { 
       if(!isset($this -> start)) { 
        if ($arr['secure']){ 
         $this -> config = parse_ini_file('C:\xampp\htdocs\project\config.ini'); 
         $this -> start = mysqli_connect($this -> config['host'], $this -> config['username'], 
                 $this -> config['password'], $this -> config['database']); 
        } 
        else { 
         $this -> start = mysqli_connect($arr['host'], $arr['username'], $arr['password'], $arr['database']); 
        } 
       } 
       if($this -> start == false) { 
        return mysqli_connect_error(); 
       } 
      } 
     } 

     class Test extends Main { 
      public function sample() { 
       $query = "SELECT id, user, 
          FROM users"; 

//Here you should use $this instead of $Main as you can access protected 
//properties of the parent from the child class. 

       $result = mysqli_query($this -> start , $query); 
       $row = mysqli_fetch_array($result); 
       echo $row['user']; 
      } 
     }  

//Instantiate Test class instead of Main as it inherits Main anyway 
//Your code also had a typo in the constructor argument. 

     $x = new Test(array("host" => '', "username" => '', "password" => '', "database" => '', "errors" => false, "secure" => true)); 

     $x -> sample(); 

請不,我沒有檢查你的代碼的MySQL的部分 - 只是一個面向對象的結構