-4

I am trying to make the switch from procedural PHP to OO PHP.

I have created a Db class that looks like this:

   class Db {

       protected static $connection;

       /*
       Attempt to connect to database. 

       @Return bool false on failure, mysqli object instance on success

       */

       public function connect() {

           if(!isset(self::$connection)) {

                //Parse DB info from configuration file
                $config = parse_ini_file('../validconfigpath/config.ini');

                //Attempt to connect to the datbase
                self::$connection = new mysqli($config['dbhost'], $config['dbuser'], $config['dbpass'], $config['dbname']);


                if(self::$connection === false) {
                    //Database connection unsuccessful, how to handle?
                    echo "Error connecting to database.<br />";
                    return false;
                }

                return self::$connection;
           }
       }

       /*
        * Query the database
        * @param $query The sql string
        * @return mixed The result of the mysqli::query() function
        */

       public function query($query) {
           //Connect to the database
           $connection = $this -> connect();

           //Query the database
           $result = $connection -> query($query);

           return $result;
       }

       /*
        * Fetch rows from the database (SELECT query)
        * @param $query The query string
        * @return bool false on failure / array Database rows on success
        * 
        */

       public function select($query) {
           $rows = array();
           $result = $this -> query($query);

           if ($result === false) {
               return false;
           }

           while($row = $result -> fetch_assoc()) {
               $rows[] = $row;
           }

           return $rows;

       }

       /*
        * Fetch last inserted ID from the database
        * @return ID of last inserted record using this connection, or 0 if no INSERT or UPDATE statements were sent
        */

       public function inserted_id() {

           $connection = $this -> connect();

           return $connection -> insert_id;

       }

       public function quote($value) {

           $connection = $this -> connect();

           return "'" . $connection -> real_escape_string($value) . "'";
       }


   }

I am trying to test the quote function, by using this code:

include_once 'Classes/DB.php';

$db = new Db();

$firstName = $db -> quote("First");
echo $firstName. "<br />";


$lastName = $db -> quote("Last");
echo $lastName. "<br />";

I get my expected output for $firstName like so:

'First'

But for my second output for $lastName I get:

Fatal error: Uncaught Error: Call to a member function real_escape_string() on null in ..\Classes\DB.php:91 Stack trace: #0 ..\index.php(11): Db->quote('Last') #1 {main} thrown in ..\Classes\DB.php on line 91

As best I can tell something is happening to $connection but I can't figure out what is wrong with connect().

Also I got to thinking is it best to just create a connection in __construct?

Soulfire
  • 4,218
  • 23
  • 33
  • 8
    Don't "fix" it. You shouldn't rely on `mysqli_real_escape_string`. Instead, you should learn about [Prepared Statements](https://en.wikipedia.org/wiki/Prepared_statement) with [parameterized queries](https://stackoverflow.com/a/4712113/5827005). I recommend switching to `PDO` (Along with the opinion of many other PHP developers). – GrumpyCrouton Nov 20 '17 at 21:21
  • 1
    `$connection` is null when you call `$connection->real_escape_string` – Matt Clark Nov 20 '17 at 21:22
  • Thanks for the suggestion, but I would still like to understand what's going wrong. – Soulfire Nov 20 '17 at 21:23
  • I see that `$connection` is null, but as I call `connect()` shouldn't it be set? Or why is that variable being unset? – Soulfire Nov 20 '17 at 21:23
  • This class is set up weirdly, you shouldn't have to connect to your database for every method. – GrumpyCrouton Nov 20 '17 at 21:26
  • ^ I do agree with that, and I hinted that at the bottom. Like should I be able to only connect once in the constructor? Brand new to OOP with PHP. – Soulfire Nov 20 '17 at 21:28
  • @Soulfire Feel free to check out my PDO class [GrumpyPDO](https://github.com/GrumpyCrouton/GrumpyPDO/blob/master/grumpypdo.php) to see how I handled it. My class also rolls parameterized queries into it in a way that is easy to use. – GrumpyCrouton Nov 20 '17 at 21:29
  • At your hunch I changed the connection to happen in `__construct` and removed the connection from each method. I then use `self::$connection` and it seems to work. I will look into your class though, if that is the better way. – Soulfire Nov 20 '17 at 21:34
  • @Soulfire Honestly PDO is generally a better solution than mysqli. It's easier to use for a ton of people, and it supports other database types than MySQL - so if you ever needed to switch database drivers, you wouldn't have to rewrite a lot of code. – GrumpyCrouton Nov 20 '17 at 21:36
  • 2
    So in first call to `quote()` the connection is established in `connect()`. Connection is never closed and in second call to `quote()` then your `if(!isset(self::$connection))` statement in `connect()` doesn't match so nothing is returned and `$connection` is set to null – miknik Nov 20 '17 at 21:36

1 Answers1

3

There is a bug in the connect() method. This method returns only for the first the a connection instance. The second call to connect() will return null. Try to move the return self::$connection; to the last line in this method.

public function connect()
{
    if (!isset(self::$connection)) {

        //Parse DB info from configuration file
        $config = parse_ini_file('../validconfigpath/config.ini');

        //Attempt to connect to the datbase
        self::$connection = new mysqli($config['dbhost'], $config['dbuser'], $config['dbpass'], $config['dbname']);

        if (self::$connection === false) {
            //Database connection unsuccessful, how to handle?
            echo "Error connecting to database.<br />";
            return false;
        }
    }

    return self::$connection;
}
odan
  • 4,757
  • 5
  • 20
  • 49