5

I have been getting the following error when I uploaded to a live server. It works OK on localhost which I thought was strange.

Fatal error: Call to a member function close() on a non-object....

The line it refers to

$stmt->close();

The connection to the DB

$connection=new mysqli($MYSQL_HOST,$MYSQL_USER,$MYSQL_PASS,$DB)or die(mysqli_error($connection));

The class itself.

function getTimes(){ //this method just pulls the results of the query and returns them as an array
    global $connection;
    $route = $this->route;
    $station = $this->station;
    $day = $this->day;

    // create a prepared statement
    if ($stmt = $connection->prepare("select time from timetable where route=? and day=? and station=?")) {
        $stmt->bind_param("sss", $route, $day, $station);   // bind parameters for markers
        $stmt->execute();   //execute query             
        $stmt->bind_result($col1);  //bind result variables
        while ($stmt->fetch()){
            $results[]=$col1;
        }
    }
    $stmt->close();//close statement
    return $results;
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
cosmicsafari
  • 3,949
  • 11
  • 37
  • 56
  • 1
    It looks like $connection->prepare() failed for some reason. If it returns false then $stmt is false, not a mysqli object like you expected. – Crashspeeder Mar 15 '12 at 14:48
  • There is also the possibility that your $connection is also null, and you are not checking for it. But that is not your error at the moment – Churk Mar 15 '12 at 14:51
  • 1
    @Churk this would result in Fatal error: call to a member function prepare() on a non-object. Either way, I agree that you should pass in the connection as a parameter: `function getTimes(mysqli $connection) {}` – cmbuckley Mar 15 '12 at 14:55
  • @cbuckley a database singleton would be better (more maintainable) than passing the connection as an argument to every function that needs the database. Like `$connection = myDatabase::getInstance();` – MrCode Mar 15 '12 at 15:41
  • @MrCode i have never implemented a singleton, would it be easy enough to get my head around? I am only just beginning to move from procedural php to OOP PHP – cosmicsafari Mar 15 '12 at 16:25
  • @MrCode I wouldn't want to get into the debate of Singleton vs DI here, but I would argue that a Singleton in this instance would make it *less* maintainable (e.g. harder to test) in the long run. My type hint assumes mysqli but better would be to use something like PDO. – cmbuckley Mar 16 '12 at 09:48
  • @cbuckley Agree about the Singleton vs DI debate. Even if going with DI, I would inject via a method as opposed to the constructor, and wouldn't type cast it as mysqli or even PDO as that would erode some of the benefits of DI. – MrCode Mar 16 '12 at 10:09
  • @JMcNelis a singleton is easy to implement, have a search for some examples. Also look into dependency injection as an alternative. – MrCode Mar 16 '12 at 10:12
  • Does this answer your question? [mysqli\_fetch\_assoc() expects parameter / Call to a member function bind\_param() errors. How to get the actual mysql error and fix it?](https://stackoverflow.com/questions/22662488/mysqli-fetch-assoc-expects-parameter-call-to-a-member-function-bind-param) – Dharman May 31 '20 at 14:02

3 Answers3

4

You should put $stmt into you if clause. There is a possiblity that if (false) and still get to your $stmt->close();

CocoaBean
  • 295
  • 7
  • 20
Churk
  • 4,556
  • 5
  • 22
  • 37
3

Your problem was that the $stmt object was instantiated as part of an if condition test. In the cases it failed, i.e. when it returns false, you were still trying to call ->close() on it anyway. I moved the method call within the if block.

Now you need to add an else clause to handle the fact that your script couldn't prepare the statement and given you say this works locally but not on your live server, I suggest there is some configuration difference causing a problem here. You need to turn on error handling with display_errors('1') and error_reporting(E_ALL). Don't forget to turn these off before letting the world at your new script. :)

function getTimes(){ //this method just pulls the results of the query and returns them as an array
        global $connection;
        $route = $this->route;
        $station = $this->station;
        $day = $this->day;

        // create a prepared statement
        if ($stmt = $connection->prepare("select time from timetable where route=? and day=? and station=?")) {
            $stmt->bind_param("sss", $route, $day, $station);   // bind parameters for markers
            $stmt->execute();   //execute query             
            $stmt->bind_result($col1);  //bind result variables
            while ($stmt->fetch()){
                $results[]=$col1;
            }
            $stmt->close();//close statement
        }

        return $results;
    }
deed02392
  • 4,799
  • 2
  • 31
  • 48
  • 1
    +1 Some error handling using `$connection->error` in the else clause will help you debug this scenario. – cmbuckley Mar 15 '12 at 14:53
  • Thanks, once i moved the close() into the if statement it then worked. Turned out i was trying to pull info for a table that had no info in it at the time which was attributing to the issue. – cosmicsafari Mar 15 '12 at 15:43
2

Move the close() call into your if statement, so that it will only be called if a $stmt was successfully created.

    // create a prepared statement
    if ($stmt = $connection->prepare("select time from timetable where route=? and day=? and station=?")) {
        $stmt->bind_param("sss", $route, $day, $station);   // bind parameters for markers
        $stmt->execute();   //execute query             
        $stmt->bind_result($col1);  //bind result variables
        while ($stmt->fetch()){
            $results[]=$col1;
        }
        $stmt->close();//close statement
    }

I suspect on your local machine you don't have errors turned on, but on the server you upload to, errors are on.

The root issue to address here is the fact that prepare() is failing. The problem there most likely is the database on the server is missing the timetable table or that table is missing one or more fields route, day or station. As said by cbuckley, check $connection->error for the full error message.

When you uploaded to the server, did you remember to also make any database structure changes on the server?

MrCode
  • 63,975
  • 10
  • 90
  • 112