I'm an inexperienced php programmer and only found out about PDO a few days ago. I'm now trying to port my website code over to using PDO, but I am getting an error when I try to use the PDO object that I create.
The error I'm getting is:
Fatal error: Call to a member function prepare() on a non-object in ... file2.php ...
The code looks like this:
index.php
class myClass
{
... variables ...
... functions ...
public function myFunction() // gets called on page load, outputs content to page
{
... stuff ...
require('file1.php');
... stuff ...
}
}
file1.php
require_once('mysql_connect.php'); // create pdo object if not created
... stuff ...
require_once('file2.php');
// I can use the PDO object in here to make queries
$output = function2(); // function2 is in file2.php
... stuff ...
file2.php
require_once('mysql_connect.php'); // create pdo object if not created
function function2()
{
... stuff ...
// PDO error occurs here
$stmt = $db->prepare(...);
makeQuery($stmt, array(...));
return $something;
}
mysql_connect.php
try
{
$db = new PDO("mysql:$dbhost=localhost;dbname=$dbname;charset=utf8", $dbuser, $dbpass, array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}
catch (PDOException $e)
{
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
function makeQuery($stmt, $array = array())
{
try
{
$stmt->execute($array);
}
catch (PDOException $e)
{
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
}
If I understand your logic right, you're trying to use the PDO object inside myFunction2 - are you passing the PDO object in as a parameter, or declaring it as a global variable? Because if you're not, it's going to be out of scope, and you won't be able to use it.
You don't need to include mysql_coonect again.
Include it just once.
index.php
-class myClass defined
--method myFunction defined (it get's called on pageload & returns the page output)
---include file1.php
----require_once('mysql_connect.php') (creates pdo object)
----*I can use the pdo object here successfully*
----require_once('file2.php')
-----function myFunction2 defined
Are DSN, username and password correct? If so, you do something like that:
$pdo = new PDO("dsn");
/* Some code... at the moment something changes $pdo value */
$pdo->prepare("QUERY");
Related
I'm dealing with a PHP application with what seems to have a peculiarity: One of its files (helpers.php) has a couple of functions that includes another file, and the included file (db_connection.php) includes the file that originally included it.
helpers.php:
<?php
function lineBreak()
{
return "\n<br>\n";
}
function saveScoreToDB($score)
{
//session_start(); // Already started
$usuario_id = $_SESSION["usuario_id"];
$etapa = $_SESSION["etapa"];
try
{
$query_etapa = "SELECT id FROM etapas WHERE numero = $etapa";
require_once "db_connection.php";
// `$db_link` works perfectly fine here:
$etapa_id = $db_link->query($query_etapa)->fetchColumn();
$query_score = "INSERT INTO score
(
usuario_id,
etapa_id,
pontos
)
VALUES
(
$usuario_id,
$etapa_id,
$score
)";
$db_link->query($query_score);
}
catch (Exception $e)
{
$_SESSION["error_message"] = $e->getMessage();
header("Location: erro.php");
}
}
function completeTest($redirectTo)
{
unset($_SESSION["etapa"]);
$usuarioId = $_SESSION["usuario_id"];
// TODO: try/catch
try
{
$queryEmailUsuario = "SELECT email FROM usuarios WHERE id = $usuarioId";
$queryNomeUsuario = "SELECT nome FROM usuarios WHERE id = $usuarioId";
require_once "db_connection.php";
// `$db_link` does *not* work here. Why?
$emailUsuario = $db_link->query($queryEmailUsuario)->fetchColumn();
$nomeUsuario = $db_link->query($queryNomeUsuario)->fetchColumn();
// Routine to send email using the variables above
}
catch (Exception $ex)
{
// TODO
}
}
db_connection.php:
<?php
require_once "db_credentials.php";
require_once "helpers.php";
// Variables used here come from `db_credentials.php`
$dsn = "mysql:host=$host;dbname=$dbname;port=3307;charset=utf8;";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
];
try
{
$db_link = new PDO($dsn, $user, $pass, $options);
}
catch (PDOException $e)
{
echo "Error connecting to the database.";
echo lineBreak();
echo $e->getMessage();
echo lineBreak();
echo lineBreak();
}
Notice how in the first script variable $db_link is used in two different functions, both of which include the file where this variable is defined. Within the first function (saveScoreToDB), the variable is available and the function works fine; but within the second (completeTest) it is not available and I get an undefined variable error.
Why is that? How to make it work?
The first require_once() works because that's the "once", but it's only in-scope in that single function call, so $db_link gets tossed out at the end of the function call and is never seen again. You can change that to require(), but creating a new connection for every single function call is... not going to work out well in the long run.
Ideally you create the connection once and then pass it in via parameters where it is needed, eg:
require_once('db_credentials.php');
saveScoreToDB($score, $db_link);
completeTest($redirectTo, $db_link)
But that might get a bit tedious, right? Well this is where classes become useful.
class MyThing {
protected $db;
public function __construct(\PDO $db) {
$this->db = $db;
}
public function saveScoreToDB($score) {
$this->db->prepare(...);
}
public function completeTest($redirectTo) {
$this->db->prepare(...);
}
}
$thing = new Mything($db_link);
$thing->saveScoreToDB(42);
$thing->completeTest('yes');
I red several questioins, but no one helped.
Fatal error: Call to a member function bind_param() on boolean in -> nope.
Fatal error: Call to a member function prepare() on null -> nope.
Fatal error: Call to a member function count() on boolean -> nope.
Fatal error Call to a member function prepare() on null -> nope.
fatal error call to a member function prepare() on resource -> nope.
Error: Call to a member function prepare() on a non-object -> nope. I am done..
I am using PHP5 and mySql with PDO:
Connection and Select works fine, but the Insert didnt want to work.
That's my function:
function AddNewUser($nickname, $email)
{
ini_set('display_errors', 1); //DELETE ME
ini_set('expose_php', 1); //DELETE ME
$pdo = EstablishDBCon();
echo "Subscribe user..<br/>";
$sql = "INSERT INTO db.table (nickname, email, insertdate, updatedate) VALUES (:nickname, :email, :insertdate, :updatedate)";
try {
$stmt = $pdo->prepare($sql); //Error at this line
//id?
$stmt->bindParam(':nickname', $nickname, PDO::PARAM_STR);
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
$stmt->bindParam(':insertdate', date("Y-m-d H:i:s"), PDO::PARAM_STR);
$stmt->bindParam(':updatedate', null, PDO::PARAM_NULL);
$stmt->exeute();
CloseDBCon($pdo);
echo "Subscribed!<br/>";
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
}
The DB pattern is:
id (int not null auto_inc) | nickname (varchar not null) | email (varchar not null) | insertdate (datetime) | updatedate (datetime)
I am new to php and I do not understand that type of error.
I marked the line inside the code, where the error is thrown:
$stmt = $pdo->prepare($sql); //Error at this line
Can someone help me?
Thanks in advance!
//EDIT:
Connection aka db_connection.php:
<?php
echo 'Establishing MySQL Connection<br/>';
$pdo = null;
$dsn = 'mysql: host=xx; dbname=xx';
$dbUser = 'xx';
$pw = 'xx';
try {
$pdo = new PDO($dsn, $dbUser, $pw);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo 'Connection established.<br/>';
}
catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
return $pdo;
?>
Here is the EstablishDBCon function:
function EstablishDBCon()
{
$pdo = include_once 'db_connection.php';
return $pdo;
}
The best way to reuse functions is to put it inside of the include file, then include it at the top of each file you'll need it. So inside of your db_connection.php, create your function:
function EstablishDBCon()
{
$pdo = false;
try{
// Put your PDO creation here
} catch (Exception $e) {
// Logging here is a good idea
}
return $pdo;
}
Now you can use that function wherever you need it. Make sure you always make sure $pdo !== false before you use it, to make sure your connection hasn't failed.
The problem is in the function EstablishDBCon(), which expects the include_once statement to return a value as if the contents of the included file are a function.
function EstablishDBCon()
{
$pdo = include_once 'db_connection.php';
return $pdo;
}
But that's not how include_once works here:
if the code from a file has already been included, it will not be included again, and include_once returns TRUE.
That's why you end up with TRUE (a boolean) in your $pdo variable.
In any event, this kind of construction makes your code really hard to follow.
I recommend only using include and friends to combine self-contained PHP functions together, or to embed parts of HTML pages in one another.
Call to a member function on boolean in this case means that $pdo is not an object, it's a boolean. So it's likely that EstablishDBCon() is returning either a true on success or false otherwise, as opposed to a database resource. Double-check the docs on that function. Here's a link to some relevant documentation on PDO that you'll need.
I need to do continuous parsing of several external stomp data streams, inserts of relevant fields into a MySql db, and regular queries from the db. All of this is in a protected environment - ie I'm not dealing with web forms or user inputs
Because I'm implementing a range of inserts into + queries from different tables, I've decided to set up a PDO active record model - following the advice of Nicholas Huot and many SO contributors.
I've got a simple repeated insert working OK, but after several days of grief can't get a prepared insert to fly. I want to use prepared inserts given there are going to be a lot of these (ie for performance).
Relevant bits of the code are :
=========
Database class :
private function __construct()
{
try {
// Some extra bad whitespace removed around =
$this->dbo = new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPSW, $options);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
}
public static function getInstance()
{
if(!self::$instance)
{
self::$instance = new self();
}
return self::$instance;
}
public function prepQuery($sql) // prepared statements
{
try {
$dbo = database::getInstance();
$stmt = new PDOStatement();
$dbo->stmt = $this->$dbo->prepare($sql);
var_dump($dbo);
}
catch (PDOException $e) {
echo "PDO prepare failed : ".$e->getMessage();
}
}
public function execQuery($sql) // nb uses PDO execute
{
try {
$this->results = $this->dbo->execute($sql);
}
catch (PDOException $e) {
echo "PDO prepared Execute failed : \n";
var_dump(PDOException);
}
}
=========
Table class :
function storeprep() // prepares write to db. NB prep returns PDOstatement
{
$dbo = database::getInstance();
$sql = $this->buildQuery('storeprep');
$dbo->prepQuery($sql);
return $sql;
}
function storexecute($paramstring) // finalises write to db :
{
echo "\nExecuting with string : " . $paramstring . "\n";
$dbo = database::getInstance(); // Second getInstance needed ?
$dbo->execQuery(array($paramstring));
}
//table class also includes buildQuery function which returns $sql string - tested ok
=======
Controller :
$dbo = database::getInstance();
$movements = new trainmovts();
$stmt = $movements->storeprep(); // set up prepared query
After these initial steps, the Controller runs through a continuous loop, selects the fields needed for storage into a parameter array $exec, then calls $movements->storexecute($exec);
My immediate problem is that I get the error message "Catchable fatal error: Object of class database could not be converted to string " at the Database prepquery function (which is called by the Table storeprep fn)
Can anyone advise on this immediate prob, whether the subsequent repeated executes should work in this way, and more widely should I change anything with the structure ?
I think your problem in this line $dbo->stmt = $this->$dbo->prepare($sql);, php want to translate $dbo to string and call function with this name from this. Actually you need to use $this->dbo.
And actually your functions not static, so i think you don't need to call getInstance each time, you can use $this.
In anticipation of mysql_query being deprecated PHP 5.5.0, I have been working on a class to handle all my DB queries :
class DataBaseClass {
//.....some other function and variables declared here....
function GetConnection() {
try {
$this->conn = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASS);
$this->conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
catch(PDOException $e) {
echo $e->getMessage();
}
return $this->conn;
}
function Query($str_sql, $arr_parameters = array()) {
try {
$this->str_mysql_error = $this->int_num_rows = $this->int_num_affected_rows = $this->int_mysql_insert_id = '';
if (count($arr_parameters) > 0) {
$obj_result = $this->conn->prepare($str_sql);
$obj_result->execute($arr_parameters);
} else {
$obj_result = $this->conn->query($str_sql);
}
}
catch(PDOException $e) {
$this->str_mysql_error = $e->getMessage() . $str_sql;
}
}
}
Then I have another class to create new user:
class AddNewUser {
//.....some other function and variables declared here....
function InsertUser() {
$str_sql = "INSERT INTO (uname, name, email, pass, user_regdate, theme) VALUES )";
$_SESSION['db_connection']->Query($str_sql, '');
}
}
Now on my main user creation page I have :
$_SESSION['db_connection'] = new DataBaseClass;
//Reason I used $_SESSION to store my DB object, is so that it can be accessible everywhere.
//Did not want to use "global" everywhere. Not sure if this is he best way???
$cls_new_user = new AddNewUser ();
$cls_new_user->InsertUser(); //Does not raise PDOExecption although SQL cleary wrong inside this method
if ( $_SESSION['db_connection']->str_mysql_error) {
//show error in error div
}
$str_sql = "SELECT some wrong SQL statment";
$_SESSION['db_connection']->Query($str_sql); // This does raise PDOExecption
if ( $_SESSION['db_connection']->str_mysql_error) {
//show error in error div
}
I'm not sure why the DB class function "Query" would not raise an exception on clearly wrong SQL when called from another class. But same function called from main page code (not inside function / class) raises and exception error.
Also, the "InsertUser" function does not execute / insert anything into DB even if SQL correct.
Could it be scope related, or the fact that I'm trying to enforce global scope of my DB object by putting it in $_SESSION ??
Am I going about this the wrong way? Reason for going class route to encapsulate all my DB calls was to avoid any deprecation issues in future - only having to update class.
Make your function this way.
function Query($str_sql, $arr_parameters = array()) {
$stmt = $this->conn->prepare($str_sql);
$stmt->execute($arr_parameters);
}
I am pretty sure that exception would be thrown
The only issue can be with catching exceptions, not throwing. And it could be caused by Namespace, not scope. To be certain, you can always prepend all PDO calls with a slash:
\PDO::FETCH_ASSOC
\PDOException
etc.
I have a pretty large site and every page is built from several included files, my site is 100% in a procedural format and I am trying to learn to use classes and a more OOP approach in PHP.
Currently my site has a header file that is included into every page, in this header is a mysql connection that is made and last the duration of the page, so if I need to run 10 different queries from different files, they all run without needing to make a new connection, so the connection is only made once.
Now that I am trying to convert to a more OO way, I am starting with writing a mysql class to connect and run queries, so I am thinking of using the classes __construct function to make a connection to mysql, I am just curious how this would work though, everytime that class gets called it would make or try to make a connection to mysql instead of just once.
Maybe I am not thinking it out clearly. Should I just initiate this class in the header 1 time and then I wont have to worry anymore?
You could create a single global object of your MySQL class and use that object everywhere. Then your constructor would only be called once.
Or you could create new objects of your MySQL class everywhere. mysql_connect doesn't open new connections if there already is one open:
If a second call is made to mysql_connect() with the same arguments, no new link will be established, but instead, the link identifier of the already opened link will be returned.
The best way I think is to use a special class to handle mysql connections and use it as a singleton. Make the constructor private and get it to return an instance of either an existing connection or a new one.
Here's my example:
class db
{
public $host;
public $user;
public $pass;
public $database;
private static $instance = false;
private function __construct()
{
}
public static function getInstance()
{
if (self::$instance === false)
{
self::$instance = new db;
}
return self::$instance;
}
public function db_connect()
{
}
public function db_disconnect()
{
}
}
This way, whenever you call: db::getInstance()->db_connect(), you are certain there's only going to be ONE instance of that connection everywhere.
Yes, you shouldn't connect multiple times. The overhead of opening and closing the connection all the time is bigger than the cost of keeping it open during the relative small time your scripts run. So you should create an instance of the class at the start and keep it in a global variable.
It's certainly not a bad idea to write your own classes as a exercise, but maybe you should look into one of the existing solutions for database connection management (Zend_Db etc.).
You can always store the database link reference in a STATIC class variable and call it whenever needed. However, PHP by itself tries to use an existing link if it exists in the memory.
I've a sample database handler code for you, ofcourse its PHP 5 and uses PDO.
<?php
// Class providing generic data access functionality
class DatabaseHandler
{
// Hold an instance of the PDO class
private static $_mHandler;
// Private constructor to prevent direct creation of object
private function __construct()
{
}
// Return an initialized database handler
private static function GetHandler()
{
// Create a database connection only if one doesn’t already exist
if (!isset(self::$_mHandler))
{
// Execute code catching potential exceptions
try
{
// Create a new PDO class instance
self::$_mHandler =
new PDO(PDO_DSN, DB_USERNAME, DB_PASSWORD);
// Configure PDO to throw exceptions
self::$_mHandler->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
self::$_mHandler->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
}
catch (PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
}
// Return the database handler
return self::$_mHandler;
}
// Clear the PDO class instance
public static function Close()
{
self::$_mHandler = null;
}
// Wrapper method for PDO::prepare
private static function Prepare($queryString)
{
// Execute code catching potential exceptions
try
{
// Get the database handler and prepare the query
$database_handler = self::GetHandler();
$statement_handler = $database_handler->prepare($queryString);
// Return the prepared statement
return $statement_handler;
}
catch (PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
}
// Wrapper method for PDOStatement::execute()
public static function Execute($sqlQuery, $params = null)
{
// Try to execute an SQL query or a stored procedure
try
{
$statement_handler = self::Prepare($sqlQuery);
// Execute query
$statement_handler->execute($params);
}
// Trigger an error if an exception was thrown when executing the SQL query
catch(PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
}
// Wrapper method for PDOStatement::fetchAll()
public static function GetAll($sqlQuery, $params = null,
$fetchStyle = PDO::FETCH_ASSOC)
{
// Initialize the return value to null
$result = null;
// Try to execute an SQL query or a stored procedure
try
{
$statement_handler = self::Prepare($sqlQuery);
// Execute the query
$statement_handler->execute($params);
// Fetch result
$result = $statement_handler->fetchAll($fetchStyle);
}
// Trigger an error if an exception was thrown when executing the SQL query
catch(PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
// Return the query results
return $result;
}
// Wrapper method for PDOStatement::fetch()
public static function GetRow($sqlQuery, $params = null,
$fetchStyle = PDO::FETCH_ASSOC)
{
// Initialize the return value to null
$result = null;
// Try to execute an SQL query or a stored procedure
try
{
$statement_handler = self::Prepare($sqlQuery);
// Execute the query
$statement_handler->execute($params);
// Fetch result
$result = $statement_handler->fetch($fetchStyle);
}
// Trigger an error if an exception was thrown when executing the SQL query
catch(PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
// Return the query results
return $result;
}
// Return the first column value from a row
public static function GetOne($sqlQuery, $params = null)
{
// Initialize the return value to null
$result = null;
// Try to execute an SQL query or a stored procedure
try
{
$statement_handler = self::Prepare($sqlQuery);
// Execute the query
$statement_handler->execute($params);
// Fetch result
$result = $statement_handler->fetch(PDO::FETCH_NUM);
/* Save the first value of the result set (first column of the first row)
to $result */
$result = $result[0];
}
// Trigger an error if an exception was thrown when executing the SQL query
catch(PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
// Return the query results
return $result;
}
}
?>
You should pass a connection object (probably PDO) around, and the various places should be able to pick that up, either as a parameter, or as a property of some central object which the others have a reference to, or something.
Having multiple connections can be useful, it seems insane that mysql_connect picks up an existing connection when you might have wanted a new one - but it's insane anyway. Just use PDO.
You can use that method if you use mysql_pconnect() function, wich will search if there's already a mysql connection and in case it finds it, it wouldn't create another one.
In alternative, if you consider nor to use instances in php, you can call php database object directly, like :
class DB {}
DB::connect($host, $user, $pass);
If you use this method, you don't need to worry about multiple connections. Of course that if you need to use several connections to more than one database at a time, you can make use of object instances, or make your class so it can take several parameters and store them all at once (not very recomemded this one)