Jump to content

Call to a member function query() on null


dunno
 Share

Go to solution Solved by mac_gyver,

Recommended Posts

Hi guys,

I am trying to implement a Pagination class for a website displaying movies. I need to have the total number of posts, but on accessing the function row_count() from class Connection I get the error: "Fatal error: Uncaught Error: Call to a member function query() on null in ..\connection.php:30 Stack trace: #0 from ...\index.php(20): Connection->row_count() #1 ..."

I only found two posts concerning this issue, and they led me to think this might be a scope issue with $db variable; $db is defined in the constructor function of the same Connection class so I thought the scope would be ok; but apparently, not.

Can anybody help? This is a real show-stopper just now. Please let me know if you need any further information.

Thanks in advance.

Sept

connection.txt index.txt

Link to comment
Share on other sites

38 minutes ago, dunno said:

I only found two posts concerning this issue, and they led me to think this might be a scope issue with $db variable; $db is defined in the constructor function of the same Connection class so I thought the scope would be ok; but apparently, not.

That's probably it, yeah.

How about pasting the relevant parts of your code into a post so we don't have to download stuff? Click the <> button, paste code, insert.

Link to comment
Share on other sites

Hi Requinix,

Sorry about my inexperience, but I know now for the future.

Thank you for your fast response. This is the Connection class

Class Connection{

  public function __construct(){
    try{
      //define database details
      $data = DB_TYPE.":host=".DB_HOST.";dbname=".DB_NAME.";";
      //new PDO object: database details, username, password
    global $db = new PDO($data,DB_USER,DB_PASS);
      show('CONNECTED!');
      //show($db); //$db is now a new PDO object
    }catch(PDOException $e){
      die($e->getMessage());
    }
  }//close constructor

  public function row_count(){

    $sql = "SELECT * FROM movies";
    $statement = $this->db->query($sql);
    $row_count = $statement->rowCount();
    show ("inside row_count");
    if($row_count){
      return $row_count;
    }else{
      return false;
    }
  } //close row_count()
}

And this, the call to row_count from index.php

<?php
      $con =new Connection();
      
      echo $con->row_count();

If $db is out of scope, I cannot possibly imagine how to correct that problem.

Thanks in advance for all your help.

Link to comment
Share on other sites

If you see any code that uses "global", as in

global $db = new PDO($data,DB_USER,DB_PASS);

then it's out of date and shouldn't be used.

This code here

$statement = $this->db->query($sql);

is trying to use the "db" thing correctly, however the "db" isn't being defined correctly.

$this->db means there is a "db" property/member variable on the class. You define it like

class Connection {
	private $db;

(it goes inside the class { } but not in any of the functions; "private" means only the Connection class can access it) and then actually give it a value with code that looks the same as how the other place was going to use it:

$this->db = new PDO($data,DB_USER,DB_PASS);

 

Link to comment
Share on other sites

Hi Requinix,

Thank you very much for your excellent answer. To be honest the expression

global $db = new PDO($data,DB_USER,DB_PASS);

was me in a desperate attempt to make the property visible to row_count(). But your solution makes total sense: the global scope within the class must be inside the class but outside any function, and the call to that property within a function must be accessed using the "$this" keyword. A simple error which I will not forget. Thank you for pointing it out.

Have a great weekend!

Sept

Link to comment
Share on other sites

2 hours ago, dunno said:

But your solution makes total sense: the global scope within the class must be inside the class but outside any function, and the call to that property within a function must be accessed using the "$this" keyword. A simple error which I will not forget. Thank you for pointing it out.

That is not quite an accurate description.

PHP has exactly two variable scopes: one for inside of functions (each function gets its own and it isn't shared with other functions) and one for outside of functions (normally referred to as the global scope, which is the same everywhere and even shared across files).

<?php

$a = 1; // global scope
echo $a; // 1

function one() {
  echo $a; // empty: $a from the global scope is not available inside this function scope so this "$a" is different
  $a = 2; // a new variable in the function scope
  echo $a; // 2
}
one();

function two() {
  echo $a; // $a from the global scope or one's scope is not available inside here either
  $a = 3; // a new variable
  echo $a; // 3
}
two();

one(); // will output the same thing as before: first echo shows nothing, second echo shows 2

echo $a; // still 1

Code in functions can use the "global" keyword to access the global scope, but this is very strongly discouraged.

With classes, their functions ("methods") have a function scope just like every other regular function has. What PHP does differently is give you a "$this" variable corresponding to the instance of the class. $this->db is using the $this variable (scoped only to the method) to access its "db" property (which has nothing to do with scope).

<?php

class Example {
  public $a;
  
  public function one() {
    echo $this->a;
    $this->a = 1;
    echo $this->a;
  }
  
  public function two() {
    echo $this->a;
  }
}

$example = new Example();
$example->one(); // first echo shows nothing because $a is undefined, second shows 1
$example->two(); // also 1

// echo $this->a; // "$this" is only available inside class methods

$example->a = 2;
$example->two(); // 2

Variable scope only matters for variables, as in things that use dollar signs, and besides the "public $a" (whose dollar sign is really more about the syntax for defining "a" in the Example class), there are only two ways that dollar signs are used in the above code: with $this and with $example.

Link to comment
Share on other sites

Thank you very much for your detailed answer; I've been trying to digest it over the weekend, and it has clarified some of my foundational wrong conceptions about PHP scope. I think every PHP beginner should read this post!

Firstly, I thought that a global variable and a local variable of the same name were the same; but as you show in example 1, the opposite is true. Secondly, the apparently simple truth that

Quote

Variable scope only matters for variables

that for a beginner is a tricky concept, is an important piece of wisdom.

There is just one point I don't fully understand; in my pagination code, if I comment out the line

private $db;

everything works exactly the same. Doesn't the property have to be defined inside a class with global scope for the function to use it with $this (as in example2)? I suspect I am missing something in this point.

Thanks for all your help.

 

Link to comment
Share on other sites

2 hours ago, dunno said:

There is just one point I don't fully understand; in my pagination code, if I comment out the line


private $db;

everything works exactly the same. Doesn't the property have to be defined inside a class with global scope for the function to use it with $this (as in example2)? I suspect I am missing something in this point.

What does your current code look like now that you added the private $db; to it?

Link to comment
Share on other sites

Thank you for your reply. Here is a snapshot of the working version of the Class Connection: note the private $db is commented out just for the test:

Class Connection{
  //private $db; //var global to class, so that both functions may use it
  public function __construct(){
    try{
      //define database details
      $data = DB_TYPE.":host=".DB_HOST.";dbname=".DB_NAME.";";
      //new PDO object: database details, username, password
      $this->db = new PDO($data,DB_USER,DB_PASS);
      show('CONNECTED!');
      //show($db); //$db is now a new PDO object
    }catch(PDOException $e){
      die($e->getMessage());
    }
  }//close constructor

  public function row_count(){

    $sql = "SELECT * FROM movies";
    $statement = $this->db->query($sql);
    $row_count = $statement->rowCount();
    //show ("inside row_count");
    if($row_count){
      return $row_count;
    }else{
      return false;
    }
  } //close row_count()

  public function display_page($start_record, $records_per_page){
    $sql="SELECT * FROM movies ORDER BY id DESC limit $start_record, $records_per_page";
    try{
      $result=$this->db->query($sql);
      if($result->rowCount()){
        while($row=$result->fetch()){
          echo '<div class="panel-heading">Title: <b>'.$row['title'].'</b>';
            echo '<div class="panel-body"';
              echo 'Director: <b>'.$row['director'].'</b>';
            echo '</div>';
          echo '</div>';
        }
      }

This code works great, with or without global property; which I cannot really understand. Also, I took your example2 code, commented out the global property, and it worked too.

Thanks for your help.

Link to comment
Share on other sites

@mac_gyver. Thank you for your answer, short and to the point. If I understand you well, the fact that I use the property is enough: there is no scope issues for a $this var within a method; certainly that would explain why the program works with $db uncommented at a global level. I am not sure I understand what you mean by   

Quote

enforce the stated visibility

I mean, why use it if it doesn't impact the functionality of the program at all? Do you mean from the human readability perspective? or, does it impact the code in some way, it becomes somehow "more" visible? Forgive my ignorance but I'd really like to get to the bottom of it; I feel it is a basic issue essential to get right from the beginning.

Thanks for all your help

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.