0

I followed the OOP in this article Using PHP with MySQL - the right way

Seems ok until I start using the placeholder variable for the object:

php > require('class_lib.php');
php > $test = new Db();

I'm using interactive PHP as it seems easier to test the code line by line. This line seems to be the problem:

php > $result = $test->query("SELECT * FROM test");
PHP Fatal error:  Call to a member function query() on a non-object in class_lib.php on line 23

This is the OOP code:

<?php 
        class Db {
                protected static $connection;

                public function connect(){
                        if (!isset(self::$connection)){
                                $configfile = realpath("database.ini");
                                echo $configfile . PHP_EOL;
                                $config = parse_ini_file($configfile);
                                $connection = mysqli_connect($config['host'],$config['user'],$config['password'],$config['dbname'],$config['port']);
                        }

                        if (self::$connection === false){
                                die ("Database connection failed.");
                                return mysql_errno(self::$connection);
                        }

                        return self::$connection;
                }

                public function query($query){
                        $connection = $this->connect();
                        $result = $connection->query($query);
                        return $result;
                }

                public function select_rows($query){
                        $rows = array();
                        $result = $this->query($query);
                        if ($result === false){
                                return false;
                        }

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

                        return $rows;
                }

                public function error(){
                        $connection = $this->connect();
                        return $connection->error;
                }

                public function quote($value){
                        $connection = $this->connect();
                        return "'" . $connection->real_escape_string($value) . "'";
                }

        }

I am also reading Classes and Objects and was hoping for some insight to help me absorb the knowledge a little faster so I can resume the more general aspects of the project.

I have not a clue what the error means. I'm following the basic ideas of OOP in PHP.

Thank you.

Ken Ingram
  • 1,538
  • 5
  • 27
  • 52

1 Answers1

1

The non-object is not referring to $test. It's referring to the $connection used in the DB->query() method. That method calls $this->connect();, but although the connect method returns self::$connection, it never actually sets it to anything, so it's null.

I assume this line is what's supposed to be setting it.

$connection = mysqli_connect($config['host'],$config['user'],$config['password'],$config['dbname'],$config['port']);

But $connection is just a local variable in the function scope. It doesn't refer to self::$connection.

It should work with self::$connection = mysqli_connect(... instead.

Don't Panic
  • 41,125
  • 10
  • 61
  • 80
  • So the author's code is faulty. Will take me a while to fully understand the idiosyncracies of PHP's OOP implementation. – Ken Ingram Sep 28 '17 at 14:38
  • Yes. I would look for a different tutorial, to be honest. One that uses prepared statements. String escaping is insufficient to prevent SQL injection. – Don't Panic Sep 28 '17 at 14:40
  • Ok. Your last line completed the thought. Any recommendations for tutorials? – Ken Ingram Sep 28 '17 at 14:42
  • I'm already reading a tutorial on prepared statements. Not so concerned about getting all things in a single place. – Ken Ingram Sep 28 '17 at 14:43
  • I was confused by the use of $connection and self::$connection, but $connection is defined globally in the object defintion as a protected static. It's not local to the function. – Ken Ingram Sep 28 '17 at 14:44
  • The `$connection` inside the connect method is not the same `$connection`, though. Add a `var_dump($connection)` before that `mysqli_connect` line, and you'll get an undefined variable notice, and `null`. Variable scope in PHP is a bit different than some other languages. – Don't Panic Sep 28 '17 at 14:49
  • Ok. I'll take a look. – Ken Ingram Sep 28 '17 at 14:50
  • Wow. You're right. The variable was set within the connect() function, but the $connection variable in the outer scope is empty. The fuck?! – Ken Ingram Sep 28 '17 at 14:54
  • Based on the manual $connection should be set as global protected static (if that's possible). – Ken Ingram Sep 28 '17 at 14:55
  • 1
    Yes. Within function scope, the only way to refer to a class variable is either `$this->variable`, or `self::$variable` for static vars. Simply using `$variable` just creates a new variable, limited to the scope of that function. – Don't Panic Sep 28 '17 at 15:00