0

I'm getting this Error by using this singleton class. Please explain me what i'm doing wrong in that? i'm trying to get the sqli object through constructor.

Fatal error: Call to private DB::__construct() from invalid context in C:\xampp\htdocs\docs\users.php on line 20

<?php

class DB
{
    #############################
    ##### Define Connection  ####
    #############################

    const HOST      = 'localhost';
    const USER      = 'root';
    const PASSWORD  = '';
    const DATABASE  = 'ali';

    #############################

    // Data Member For MySQLi Database Connection
    private static $mysqli = NULL;

    // Database Connection
    private function __construct()
    {
        @self::$mysqli = new mysqli(self::HOST, self::USER, self::PASSWORD, self::DATABASE);

        if (self::$mysqli->connect_error) {
            throw new Exception("<b>Database Connect Error: </b>" . self::$mysqli->connect_error);
        }
        if (self::$mysqli->error) {
            throw new Exception("<b>Database Select Error: </b>" . self::$mysqli->error);
        }

        echo "<span style='color: green; font-size: 18px; font-weight: bold'>Connected</span>
        <br>"; // For testing //

        return self::$mysqli;
    }

    // Class Level Static Function to Get Database Connection
    public static function get_connection()
    {
        if ( ! isset(self::$mysqli) )
        {
            self::$mysqli = new self();
        }

        return self::$mysqli;
    }
}

?>

my 2nd file where i'm using this class

<?php

require_once 'DB.php';

class users extends DB
{
    public function get_results()
    {
        $sqli = DB::get_connection();

        $user_data = $sqli->query("SELECT * FROM `users`");

        while($row = $user_data->fetch_object())
        {
            echo $row->name . "<br>";
        }
    }
}

$user = new users;
try {
    $user->get_results();
} catch (Exception $e) {
    echo $e->getMessage();
}
?>
Ejaz
  • 8,719
  • 3
  • 34
  • 49
Zayn Ali
  • 4,765
  • 1
  • 30
  • 40
  • 1
    Shouldn't `__construct()` be public? – Jerbot May 13 '14 at 23:55
  • you should use _only_ composition instead of inheritance. Do not inherit user from DB class (you're using composition already) – Ejaz May 13 '14 at 23:58
  • Now i'm getting this Error Fatal error: Call to undefined method DB::query() in C:\xampp\htdocs\docs\users.php on line 11 – Zayn Ali May 14 '14 at 00:01
  • yes but i'm trying to get the mysqli object through DB constructor so that i can use it outside the class like in user.php. how to do this? – Zayn Ali May 14 '14 at 00:08
  • (Singletons are so bad. What if you have 2 dbs later on? If you want 1 of something, just make 1. Don't use a crappy design pattern that'll bite you in the butt 100.000 LOC later. Just my humble opinion.) – Rudie May 14 '14 at 00:25

1 Answers1

2

if you're not aiming to build that typical database connection singleton then following code will achieve what you want

  class DB
  {
     const HOST = 'localhost';
     const USER = 'root';
     const PASSWORD = '';
     const DATABASE = 'yourdb';

     private static $mysqli = null;

     private function __construct() {
        //an empty private constructor to prevent creating instances of this class
     }

     public static function get_connection() {
        if(!self::$mysqli) {
           //create mysqli object here and return instead of (typically returned) self instance 
           $conn = new mysqli(self::HOST, self::USER, self::PASSWORD, self::DATABASE);

           if($conn->connect_error) {
              throw new Exception("<b>Database Connect Error: </b>" . $conn->connect_error);
           }
           if($conn->error) {
              throw new Exception("<b>Database Select Error: </b>" . $conn->error);
           }
           self::$mysqli = $conn;
        }

        return self::$mysqli;
     }
  }

user class doesn't need any changes, except for removing extends DB, to eliminate the error.

Update

  class DB
  {
     const HOST = 'localhost';
     const USER = 'root';
     const PASSWORD = '';
     const DATABASE = 'yourdb';

     private $mysqli = null;

     private function __construct() {
        $conn = new mysqli(self::HOST, self::USER, self::PASSWORD, self::DATABASE);

        if($conn->connect_error) {
           throw new Exception("<b>Database Connect Error: </b>" . $conn->connect_error);
        }
        if($conn->error) {
           throw new Exception("<b>Database Select Error: </b>" . $conn->error);
        }
        $this->mysqli = $conn;
     }


     /**
      * @return DB
      */
     public static function get_connection() {
        /**
         * @static $DB DB a static variable that is not class member but will be _shared_ across all calls to  DB::get_connection()
         *
         * WTF? http://stackoverflow.com/questions/6601027/php-and-static-variables-in-object-member-functions
         */
        static $DB = null;
        if($DB == null) {
           $DB = new DB();
        }

        return $DB;
     }


     /**
      * A wrapper for internal database object/connection/resource's query method
      * @param $sql String the sql query
      *
      * @return bool|mysqli_result
      */
     public function query($sql) {
        return $this->mysqli->query($sql);
     }
  }
Ejaz
  • 8,719
  • 3
  • 34
  • 49
  • Thanks Ejay for answering. I had made this code before, i's just trying to do it with a constructor and a typical method. Can u demostrate it with a constructor method? – Zayn Ali May 14 '14 at 01:57