I'm having problem with global variable in PHP. I have mysqli config file which contains only following data:
$mysqli = new mysqli("localhost", "user", "pass", "db");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
I have the following class on another file:
class user{
function username_exists($username){
global $mysqli;
if ($stmt = $mysqli->prepare("SELECT username FROM users WHERE username=?")) {
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
$count=$stmt->num_rows;
$stmt->close();
}
return ($count > 0 ? true : false);
}
...
some more functions
...
}
Now this works fine, but in my previous question on SO, i was told that it is a bad practice to access global variable like I'm doing in above class. So, I'm trying to pass the global variable in the constructor, in following way:
private $mysqli;
function __construct()
{
global $mysqli;
$this->mysqli = $mysqli;
}
function username_exists($username){
//global $mysqli;
if ($stmt = $this->mysqli->prepare("SELECT username FROM users WHERE username=?")) {
And I get the following error:
Fatal error: Call to a member function prepare() on a non-object in...(line number)
Can you please tell me whats problem with it and how this can be fixed? Thanks.
Edit: Sorry for the spelling mistake of __construct. It was only mistake typing here, and the error isnt because of that.
Well... having global in your constructor kindof beats the point. Consider passing it in as a parameter __construct($mysqli).
public function __construct($mysqli)
{
$this->mysqli = $mysqli;
}
What you're trying to do here is called dependency injection.
I think the problem is you misstyped __construct try changing your __cuntruct to the right name for the constructor.
The global in username_exists is also useless.
You should also write a constructor which takes the variable as argument and avoid using global completly :
class User {
var $mysqli;
function __construct($mysqli) {
$this->mysqli = $mysqli;
}
[ ... some functions ... ]
}
You must create your object like this :
$myuser = new User($mysqli);
$myUser->prepare();
Your constructor is not getting called because it is not the constructor at all
__cuntruct
should be
__construct
Couple of things. I think it would work OK if you changed __cuntruct to __construct.
You're still using the global declaration inside the username_exists function. Why not just pass the $mysqli variable in the constructor?
function _construct($mysqli) {
$this->mysqli = $mysqli;
}
then you have no globals in the class.
The code as written was not really what the others on SO were attempting to encourage you to do.
function __construct($mysql_handler){
$this->mysql = $mysql_handler;
}
This is passing in the parameter into the object scope at construction. When you create an instance of your object, you would pass in the MySQL handle.
$mysqli = new mysqli("localhost", "user", "pass", "db");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$u = new User($mysqlli);
Then you should be able to call mysqli member functions on the property itself.
Your constructor is also misspelled. It will only work properly with the magic method name __construct().
Remove global $mysqli; in the function username_exists(), it does not makes sense.
The global $mysqli; is not required/does not makes sense since you want this variable to store the reference the connection IN THE CONTEXT of your object.
change __cuntruct() to __construct()
Related
I'm newbie here. I tried to solve this for a day and searching all the way but I still couldn't.
The error shown up
Notice: Undefined variable: db (in dbFunction)
Fatal error: Call to a member function query() on a non-object (in dbFunction)
and code is
dbConnect.php
class dbConnect{
public $db;
public function __construct(){
$db = new mysqli("localhost", "root", "", "onlineshopping");
$db->set_charset("charset");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
}
}
dbFunction
class dbFunction extends dbConnect {
function __construct() {
}
public $db;
public function UserRegister($fname, $lname, $tel, $email, $pass){
$pass = md5($pass);
$db->query("INSERT INTO member(fname, lname, tel, email, password) values('".$fname."','".$lname."','".$tel."','".$email."','".$pass."')") or die(mysqli_error());
return $db;
}
}
First of all, your $db is a local variable in the __construct() method and not a class property and second, as pointed by #wogsland it gets overwritten by the child.
You might want to review a bit the OO basics
dbConnect.php
class dbConnect{
public $db;
public function __construct(){
$this->db = new mysqli("localhost", "root", "", "onlineshopping");
$this->db->set_charset("charset");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
}
}
dbFunction
class dbFunction extends dbConnect {
public function UserRegister($fname, $lname, $tel, $email, $pass){
$pass = md5($pass);
$this->db->query("INSERT INTO member(fname, lname, tel, email, password) values('".$fname."','".$lname."','".$tel."','".$email."','".$pass."')") or die(mysqli_error());
}
}
Notice the replacement of $db with $this->db in both methods.
edit:
My post was an exact answer to your question but, as others have pointed in comments, there are quite a few things you need to improve and my hope was that this code is for your own personal play not something for 'production'.
So, directly related to the code example, two obvious things you might want to expand:
at least escape all your input to avoid sql injection
don't use MD5 for hashing passwords as it is very weak, check a more secure way to hash passwords
Your dbFunction class redefines __construct() to do nothing, so the $db property remains undefined. If you don't want to change the constructor in dbFunction, just omit it and the parent constructor will be used. If, on the other hand, you want to add to the functionality of the constructor then make sure to call the parent constructor:
function __construct() {
parent::__construct();
// additional dbFunction construction here
}
First of all, there's no need to make dbFunction a child class of dbConnect. They aren't related at all. In fact, I couldnt find any need to make dbConnect a class at all. All you need is the module __construct(). I would propose that you read up on OOP concepts :)
Still, answering your question - your __construct() function in dbConnect should return the db variable! You can assign this return value to your db variable in dbFunction.
Add the following line to your dbConnect's __construct() outside the if clause:
return $db;
And then instantiate an object of your class dbConnect in your dbFunction and assign db to that return value. (I'm assuming that dbFunction is not a child of dbConnect now...)
dbConn = new dbConnect()
db = dbConn.__construct()
First learn some basics of OO programming it seems like you should first read about objects and instances before using them in any fashion. Try this http://litove.com/object-oriented-programming-2/ you will find all your answers.
Here is the code:
if(!class_exists('DB')) {
class DB {
public function __construct() {
$mysqli = new mysqli('localhost','root','','cms');
if ($mysqli->connect_errno) {
printf("Connect failed %s\n",$mysqli->connect_error);
exit();
}
$this->connection = $mysqli;
}
public function insert() {
$query = "INSERT INTO post_title
VALUES ('title')";
$result = $this->connection->query($query);
return $result;
}
}
}
?>
I just dont understand how two -> is being used in $this->connection->query($query);. Also dont understand query($query). Is both query and $query the same? I'm just over all lost with this code any input much appreciated
I think i got it now. query is a built in method i believe. $this->connection is used to grab the object $mysqli from the constructor method, to then call the query method which takes in a query parameter hence the reason $query was passed in. I could be completely wrong or somewhat wrong, any input or further explanation I may not realize greatly appriciated.
This question already has answers here:
Call to a member function prepare() on a non-object PHP Help [duplicate]
(8 answers)
Closed 9 years ago.
Heres my code to connect to the database
function createConnection($DB_USER, $DB_PASSWORD){
$dbc = new PDO('mysql:host=****', $DB_USER, $DB_PASSWORD);
}
and below and is the code for a function being called
function checkIfUserExists($dbc, $username, $table){
global $dbc;
$stmt = $dbc->prepare("SELECT * FROM ? WHERE username = ?");
$stmt = bindParam(1, $table);
$stmt = bindParam(2, $username);
$stmt->execute();
}
below is the code i use to call them
$connect = new databaseOperations;
$connect->createConnection($DB_USER, $DB_PASSWORD);
$connect->checkIfUserExists($dbc, login, Username);
my question is why am i getting the call to a member function prepare() on a non-object error when the page loads?
You get that because the $dbc you pass to the checkIfUserExists method is not available in the global scope, only in the scope where it is created (in this case, the scope of createConnection).
The solution is simple: Never ever use globals in your code and the last code where you should use globals is in OOP code.
Use something like this:
class DatabaseOperations
{
private $dbc;
public function createConnection(...)
{
$this->dbc = new PDO(...);
}
public function checkIfUserExists(...)
{
$this->dbc->prepare(...);
// ...
}
}
$db = new DatabaseOperations();
$db->createConnection(...);
$db->checkIfUserExists(...);
Or return the $dbc variabele in the createConnection function and pass that to the other functions.
Important side note: This is surely not the way you should use classes. Read something about OOP and program like that. In that case, you usually have a method on the User (Active Record) or UserMapper (DataMapper) object to check if it exists.
function createConnection($DB_USER, $DB_PASSWORD){
$dbc = new PDO('mysql:host=****', $DB_USER, $DB_PASSWORD);
return $dbc; // <---- add this...
}
function checkIfUserExists($dbc, $username, $table){
// ---> no need to use global, because you pass $dbc as an argument
calling...
$dbc = $connect->createConnection($DB_USER, $DB_PASSWORD);
This question already has answers here:
Executing mysqli_query inside a function
(2 answers)
Closed 7 months ago.
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?
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:
A quick google search to get you started
Doctrine ORM - A complete database access library with full ORM (Object Mapping)
ADODB - A database agnostic database access library
Pear MDB2 - Another database access library
Full Frameworks:
Zend Framework
Lithium Framework
Code Igniter
(really there are a lot more, I'm not going to bother listing any more since that's another question all together...)
Really, the choices are endless. Find something you like, and stick with it. It really will make your life easier...
$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.
Try to add global $DBH; in the function, or add it to the function's parameters.
selectInfo($DBH);
function selectInfo($DBH,$limit, $offset){
$stmt = $DBH->prepare("SELECT * FROM information LIMIT ?,?");
$stmt->bind_param("ii", $limit, $offset);
$stmt->execute();
}
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(...);
...
}
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());
}
Making $DBH global is not healthy...
except that you can make your $DBH protected in class and set it to null..
and use it..
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...";
}
I am trying to convert code from mysql to mysqli.
The code uses a single mysql_connect in a file which is included by every other file.
mysql_connect returns a MySQL link identifier that is a superglobal so you can rely on having a database connection available in any of your own functions.
It looks like with mysqli_connect this is not the case, the object returned isn't global.
Does this mean I have to add : global $mysqli; at the top of every function, or is there an way of making it a superglobal?
Relying on the fact that PHP will use the last opened connection resource if you don't specify one, is probably not a very good idea.
What happens if your application changes and you need two connections, or the connection is not there?
So it seems you need to do some refactoring anyway.
Here's a solution similar to Karsten's that always returns the same mysqli object.
class DB {
private static $mysqli;
private function __construct(){} //no instantiation
static function cxn() {
if( !self::$mysqli ) {
self::$mysqli = new mysqli(...);
}
return self::$mysqli;
}
}
//use
DB::cxn()->prepare(....
I usually make a function:
$mysqli = new mysqli(...);
function prepare($query) {
global $mysqli;
$stmt = $msqyli->prepare($query);
if ($mysqli->error()) {
// do something
}
return $stmt;
}
function doStuff() {
$stmt = prepare("SELECT id, name, description FROM blah");
// and so on
}
and then call that. That being said, I've since abandoned mysqli as being too bug-ridden to be considered usable. Shame really.
A very simple way to do this would be with a fixed database class, just to hold the mysqli connection object:
class Database {
public static $connection;
}
Database::$connection = new mysqli(HOST, USERNAME, PASSWORD, DATABASE);
Then you can access it in the normal ways:
$sql = 'SELECT * FROM table';
$result = Database::$connection->query($sql);
$result = mysqli_query(Database::$connection, $sql);
echo 'Server info ' . mysqli_get_server_info(Database::$connection);
To introduce some oop to you and solve your problem, you could use a class like this:
class MyDatabase
{
private static $_connection;
public static function connect()
{
$mysqli = new mysqli(...);
self::$_connection = $mysqli;
}
public static function getConnection()
{
return self::$_connection;
}
}
In your database-connection file you would load this class and execute MyDatabase::connect(); once.
To get the $mysqli-connection anywhere in your script, just call MyDatabase::getConnection();.