dunno Posted June 4, 2021 Share Posted June 4, 2021 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 Quote Link to comment Share on other sites More sharing options...
requinix Posted June 4, 2021 Share Posted June 4, 2021 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. Quote Link to comment Share on other sites More sharing options...
Barand Posted June 4, 2021 Share Posted June 4, 2021 Wht the connection class to call a connection class? Why not just... $db = new PDO( .... ); Job done. Quote Link to comment Share on other sites More sharing options...
dunno Posted June 5, 2021 Author Share Posted June 5, 2021 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. Quote Link to comment Share on other sites More sharing options...
requinix Posted June 5, 2021 Share Posted June 5, 2021 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); Quote Link to comment Share on other sites More sharing options...
dunno Posted June 5, 2021 Author Share Posted June 5, 2021 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 Quote Link to comment Share on other sites More sharing options...
requinix Posted June 5, 2021 Share Posted June 5, 2021 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. Quote Link to comment Share on other sites More sharing options...
dunno Posted June 7, 2021 Author Share Posted June 7, 2021 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. Quote Link to comment Share on other sites More sharing options...
requinix Posted June 7, 2021 Share Posted June 7, 2021 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? Quote Link to comment Share on other sites More sharing options...
dunno Posted June 7, 2021 Author Share Posted June 7, 2021 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. Quote Link to comment Share on other sites More sharing options...
mac_gyver Posted June 7, 2021 Share Posted June 7, 2021 php creates class properties (variables) without having to define them. the only thing defining them does is enforce the stated visibility. Quote Link to comment Share on other sites More sharing options...
dunno Posted June 8, 2021 Author Share Posted June 8, 2021 @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 Quote Link to comment Share on other sites More sharing options...
Solution mac_gyver Posted June 8, 2021 Solution Share Posted June 8, 2021 https://www.php.net/manual/en/language.oop5.visibility.php Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.