Unable to use PDO inside class - php

I've a simple class, User which requires database access. I also require database access in several other classes, so my class.user.php looks like this:
include "config.php"
class User {
public $db;
public function __construct(PDO $db){
$this->db = $db;
global $db;
}
function LastLogin(){
// global $db; // if I uncomment this, it works for this function.
$pdo = $db->prepare("SELECT last_login FROM users WHERE username = ?");
$pdo->execute(array($username));
while($r = $pdo->fetchObject()){
echo $r->last_login;
}
}
}
Config.php looks like this:
$dsn = "mysql:host=localhost;dbname=db;charset=utf8";
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
$db = new PDO($dsn,'user','pass', $opt);
So let's say I have page called userdetails.php, and I want to know when the user has last logged in.
$user = new User($db);
$user->LastLogin();
This results in a error message like this:
Notice: Undefined variable: db in /home/www/class.user.php on line 12
Fatal error: Call to a member function prepare() on a non-object in/home/www/class.user.php on line 12
So I'm having problems with using pdo inside the class. It makes no sense to type "global $db" to every function, so what am I doing wrong?

As stated in the comments, remove the line:
global $db;
Also, you don't need to pass the PDO either.
And instead of trying to reference it as
$db->prepare(....)
You want to reference it as:
$this->db->prepare(....)
since you're instantiating it as a variable accessible within the class.

try this
include "config.php"
class User {
public $db;
public function __construct($db){
$this->db = $db;
}
function LastLogin(){
$pdo = $this->db->prepare("SELECT last_login FROM users WHERE username = ?");
$pdo->execute(array($username));
while($r = $pdo->fetchObject()){
echo $r->last_login;
}
}
}
The global $db is definitely not required and is bad practice as it destroys the encapsulation of a class.
The type hint PDO in __construct(PDO $db) is also not actually legal as far as I know.
And while you have a property of $db and loaded it with the correct handle, to use it chnage this
$pdo = $db->prepare("SELECT last_login FROM users WHERE username = ?");
To
$pdo = $this->db->prepare("SELECT last_login FROM users WHERE username = ?");
So you are using/addressing it correctly.

global $db is the problem. Loose it and it all should work.

Remove global $db from your constructor.
Use $this->db instead of $db in function LastLogin

Related

how to consolidated database connection into one file in php [duplicate]

I really hope someone can help me figure out what I am missing. I have upgraded my installation from PHP 5.6 to 7.0 and this has forced me to update from Mysql to Mysqli which for some reason has broken my setup.
I researched and followed this guide "Using MySQLi in other classes": Using MySQLi in other classes
I am writing as a last resort and have looked at other sites as well but it seems like the problem comes some where else from.
First I have a database class:
private $serverName = "localhost";
private $userName = "DBUserName";
private $pass = "UserPassword";
private $database = "SelectedDB";
public $conn;
public function __construct(){
$this->conn = new mysqli($this->serverName, $this->userName,$this->pass,$this->database);
}
Then I have an API class where I want to access this connection which looks like
require_once 'Database.php';
class MyAPI{
private $db;
public function __construct($request_uri, $postData, $origin) {
$this->db = new Database();
}
and lastly i try to call it from a function:
$getUserResult = mysqli_query( $this->db->conn, $getUserQry);
When ever I call $this->db->conn I get an internal server error 500
If I create the database connection in the MyAPI class there is no issues which seems odd to me.
I hope someone can point me in a direction.
UPDATE:
I corrected a spelling error in the script and now I get 200 but the value still continues to be null from the query mysqli_query.
If i create the $dbtest = new database(); and use that instead it works fine. Is there someway to get it to work inside the constructor with the reference to $db?
There are several bad practices that led you to this error.
Clearly, extending User from a Database is a wrong move. Also, the whole Database class is rather useless as it doesn't do anything useful.
Hence I would suggest to
get rid of the useless Database class.
create a single $db instance from vanilla mysqli.
pass it as a constructor parameter into every class that needs a database connection
database.php:
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$db = new mysqli("localhost", "DBUserName", "UserPassword", "SelectedDB");
$db->set_charset('utf8mb4');
myapi.php
<?php
class MyAPI
{
protected $db;
public function __construct($db, $request_uri, $postData, $origin)
{
$this->db = $db;
}
public function getUser($id)
{
$sql = "SELECT * FROM users where id=?";
$stmt = $this->db->prepate($sql);
$stmt->bind_param("s", $id);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_assoc();
}
}
app.php
<?php
# require_once 'Database.php';
# require_once 'myapi.php';
require 'vendor/autoload.php'; // autoloading is a must
$api = new MyAPI($db, $request_uri, $postData, $origin);
$user = $api->getUser($_POST['id']);

Prepared statement in OOP [duplicate]

I really hope someone can help me figure out what I am missing. I have upgraded my installation from PHP 5.6 to 7.0 and this has forced me to update from Mysql to Mysqli which for some reason has broken my setup.
I researched and followed this guide "Using MySQLi in other classes": Using MySQLi in other classes
I am writing as a last resort and have looked at other sites as well but it seems like the problem comes some where else from.
First I have a database class:
private $serverName = "localhost";
private $userName = "DBUserName";
private $pass = "UserPassword";
private $database = "SelectedDB";
public $conn;
public function __construct(){
$this->conn = new mysqli($this->serverName, $this->userName,$this->pass,$this->database);
}
Then I have an API class where I want to access this connection which looks like
require_once 'Database.php';
class MyAPI{
private $db;
public function __construct($request_uri, $postData, $origin) {
$this->db = new Database();
}
and lastly i try to call it from a function:
$getUserResult = mysqli_query( $this->db->conn, $getUserQry);
When ever I call $this->db->conn I get an internal server error 500
If I create the database connection in the MyAPI class there is no issues which seems odd to me.
I hope someone can point me in a direction.
UPDATE:
I corrected a spelling error in the script and now I get 200 but the value still continues to be null from the query mysqli_query.
If i create the $dbtest = new database(); and use that instead it works fine. Is there someway to get it to work inside the constructor with the reference to $db?
There are several bad practices that led you to this error.
Clearly, extending User from a Database is a wrong move. Also, the whole Database class is rather useless as it doesn't do anything useful.
Hence I would suggest to
get rid of the useless Database class.
create a single $db instance from vanilla mysqli.
pass it as a constructor parameter into every class that needs a database connection
database.php:
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$db = new mysqli("localhost", "DBUserName", "UserPassword", "SelectedDB");
$db->set_charset('utf8mb4');
myapi.php
<?php
class MyAPI
{
protected $db;
public function __construct($db, $request_uri, $postData, $origin)
{
$this->db = $db;
}
public function getUser($id)
{
$sql = "SELECT * FROM users where id=?";
$stmt = $this->db->prepate($sql);
$stmt->bind_param("s", $id);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_assoc();
}
}
app.php
<?php
# require_once 'Database.php';
# require_once 'myapi.php';
require 'vendor/autoload.php'; // autoloading is a must
$api = new MyAPI($db, $request_uri, $postData, $origin);
$user = $api->getUser($_POST['id']);

About OOP, using PHP [duplicate]

I really hope someone can help me figure out what I am missing. I have upgraded my installation from PHP 5.6 to 7.0 and this has forced me to update from Mysql to Mysqli which for some reason has broken my setup.
I researched and followed this guide "Using MySQLi in other classes": Using MySQLi in other classes
I am writing as a last resort and have looked at other sites as well but it seems like the problem comes some where else from.
First I have a database class:
private $serverName = "localhost";
private $userName = "DBUserName";
private $pass = "UserPassword";
private $database = "SelectedDB";
public $conn;
public function __construct(){
$this->conn = new mysqli($this->serverName, $this->userName,$this->pass,$this->database);
}
Then I have an API class where I want to access this connection which looks like
require_once 'Database.php';
class MyAPI{
private $db;
public function __construct($request_uri, $postData, $origin) {
$this->db = new Database();
}
and lastly i try to call it from a function:
$getUserResult = mysqli_query( $this->db->conn, $getUserQry);
When ever I call $this->db->conn I get an internal server error 500
If I create the database connection in the MyAPI class there is no issues which seems odd to me.
I hope someone can point me in a direction.
UPDATE:
I corrected a spelling error in the script and now I get 200 but the value still continues to be null from the query mysqli_query.
If i create the $dbtest = new database(); and use that instead it works fine. Is there someway to get it to work inside the constructor with the reference to $db?
There are several bad practices that led you to this error.
Clearly, extending User from a Database is a wrong move. Also, the whole Database class is rather useless as it doesn't do anything useful.
Hence I would suggest to
get rid of the useless Database class.
create a single $db instance from vanilla mysqli.
pass it as a constructor parameter into every class that needs a database connection
database.php:
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$db = new mysqli("localhost", "DBUserName", "UserPassword", "SelectedDB");
$db->set_charset('utf8mb4');
myapi.php
<?php
class MyAPI
{
protected $db;
public function __construct($db, $request_uri, $postData, $origin)
{
$this->db = $db;
}
public function getUser($id)
{
$sql = "SELECT * FROM users where id=?";
$stmt = $this->db->prepate($sql);
$stmt->bind_param("s", $id);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_assoc();
}
}
app.php
<?php
# require_once 'Database.php';
# require_once 'myapi.php';
require 'vendor/autoload.php'; // autoloading is a must
$api = new MyAPI($db, $request_uri, $postData, $origin);
$user = $api->getUser($_POST['id']);

Call to a member function prepare() on a non-object PHP [duplicate]

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);

Call to a member function prepare() on a non-object PHP Help [duplicate]

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...";
}

Categories