12

I am trying to write a PHP function. It is very simple. It is just a prepared statement that queries the database, but I can not get this to work. I keep recieving the error Call to a member function prepare() on a non-object. here is the code:

$DBH = new mysqli("host", "test", "123456", "dbname");
function selectInfo($limit, $offset){
    $stmt = $DBH->prepare("SELECT * FROM information LIMIT ?,?");
    $stmt->bind_param("ii", $limit, $offset);
    $stmt->execute();
    }
selectInfo();

Any time I call the function i get that error. Can someone please help?

mcbeav
  • 11,893
  • 19
  • 54
  • 84

8 Answers8

44

It's a scoping error. You're making $DBH a global variable. So when you enter the function, the global variable is not available. You have 5 real options.

1. Use the global keyword

function doSomething() {
    global $DBH;
    //...

This is not a good idea, since it makes maintenance and testing a PITA. Imagine trying to debug that function call. You now need to go find out where $DBH is defined to try to figure out what's going on...

2. Make $DBH a parameter to the function

function doSomething(MySQLi $DBH) {

It has the advantage of being explicit. But it's still not great since the calling code then needs to keep track of the global variable.

3. Create a function to "get" the $DBH object

function getDBH() {
    static $DBH = null;
    if (is_null($DBH)) {
        $DBH = new mysqli(...);
    }
    return $DBH;
}

function doSomething() {
    $DBH = getDBH();
}

This has the advantage of getting around the global variable problem completely. But it's also hard to have multiple connections or re-use any of the code for other connections.

4. Create a class to wrap database access

class Database {
    public function __construct($host, $user, $pass) {
        $this->DBH = new MySQli($host, $user, $pass);
    }
    public function doSOmething() {
        $this->DBH->foo();
    }
}

This encapsulates everything for you. All database access will go through a single class, so you don't need to worry about global variable access or anything else.

5. Use a pre-built class/framework

This is the best option, since you don't need to worry about doing it yourself.

Database Access Classes:

Full Frameworks:

Really, the choices are endless. Find something you like, and stick with it. It really will make your life easier...

Dharman
  • 30,962
  • 25
  • 85
  • 135
ircmaxell
  • 163,128
  • 34
  • 264
  • 314
  • it did't worked for me : http://stackoverflow.com/questions/40080426/fatal-error-call-to-a-member-function-prepare-on-a-non-object-in-but-value – fresher Oct 17 '16 at 12:35
  • Can be move the global option at least down the list, and emphasize the parameter option as preferred? – Your Common Sense Mar 01 '22 at 06:23
6

$DBH is not in scope. You either want to define $DBH as global in the function:

$DBH = new mysqli("host", "test", "123456", "dbname");
function selectInfo($limit, $offset){
    global $DBH;
    $stmt = $DBH->prepare("SELECT * FROM information LIMIT ?,?");
    $stmt->bind_param("ii", $limit, $offset);
    $stmt->execute();
}

or as ircmaxell pointed out in his excellent answer have a function which returns a static instance of $DBH.

simeg
  • 1,889
  • 2
  • 26
  • 34
Jim
  • 22,354
  • 6
  • 52
  • 80
  • Thanks. How would i make that a global and still keep things secure? Would i wrap the connection in a function and then assign a variable to it like function connect(){ new myqsli("host", "test", "123456", "dbname")} $DBH = new connect(); (The connection variables are actually hidden in another file.) – mcbeav Dec 16 '10 at 17:19
  • Yeah, I would make some kind of function and grab the connection from there. – Jim Dec 16 '10 at 17:22
  • @ircmaxell Done. You are right of course. Making a new connection for every method call is a bad idea. – Jim Dec 16 '10 at 17:29
3

Try to add global $DBH; in the function, or add it to the function's parameters.

István Ujj-Mészáros
  • 3,228
  • 1
  • 27
  • 46
3
selectInfo($DBH);

function selectInfo($DBH,$limit, $offset){
    $stmt = $DBH->prepare("SELECT * FROM information LIMIT ?,?");
    $stmt->bind_param("ii", $limit, $offset);
    $stmt->execute();
    }
Sandeepan Nath
  • 9,966
  • 17
  • 86
  • 144
3

That's simply. $DBH doesn't exist within selectInfo() function. Variable defined in global scope won't be visible within function and vice-versa. Read more about variables scope on manual pages.

How to solve it? Pass that variable as a argument of the function:

$dbh = new MySQLi(...);

function selectInfo(MySQLi $dbh, $limit, $offset) {
    $stmt = $dbh->prepare(...);
    ...
}
Crozin
  • 43,890
  • 13
  • 88
  • 135
3

Make sure the connection is successful.

$DBH = @new mysqli("host", "test", "123456", "dbname");

if ($DBH->connect_errno) {
    die('Connect Error: ' . $DBH->connect_errno);
}

or

$DBH = @mysqli_connect("host", "test", "123456", "dbname");

if (!$DBH ) {
    die('Connect Error: ' . mysqli_connect_errno());
}
madkris24
  • 483
  • 1
  • 4
  • 16
0

Making $DBH global is not healthy... except that you can make your $DBH protected in class and set it to null.. and use it..

0
class PDOconnect extends PDO{

protected $con=null;

    public function __construct(){
              try {      

                     $this->con= new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD ); //our new PDO Object

                      $this->con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );                       
                      $this->con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );                     
                      $this->con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
                      echo "hi.. you are connected succcessfully...";
                  }