using PDO with php and mysql in class - php

i am trying to use PDO in php using classes.
so i have defined one config file like that
<?php
global $configVars;
$configVars['online'] = false;
if(($_SERVER['SERVER_NAME'])!='localhost' and ($_SERVER['SERVER_NAME'])!='abc')
{
$configVars['dbhost'] = "localhost";
$configVars['dbuser'] = "dbuser";
$configVars['dbpassword'] = "dbpass";
$configVars['dbname'] = "dbname";
}
?>
then i have defined class to connect the database
<?php
class dbClass{
var $dbHost,
$dbUser,
$dbName,
$dbPass,
$dbTable,
$dbLink,
$resResult,
$dbh,
$dbPort;
function dbClass(){
global $configVars;
$this->dbHost = $configVars['dbhost'];
$this->dbUser = $configVars['dbuser'];
$this->dbPass = $configVars['dbpassword'];
$this->dbName = $configVars['dbname'];
$this->connect_PDO();
}
function connect_PDO(){
try {
$dbh = new PDO('mysql:host='.$this->dbHost.';dbname='.$this->dbName.'', $this->dbUser, $this->dbPass);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "Connected.";
}
catch(PDOException $e) {
echo "I'm sorry Charlie, I'm afraid i cant do that.";
file_put_contents('PDOErrors.txt', $e->getMessage(), FILE_APPEND);
$dbh = null;
}
}
}
?>
now i have defined another class to select the records from table
<?
class cms extends dbClass
{
function get_rec($id=0)
{
($id==0?$addQuery="":$addQuery=" where id =".$id);
$statement = $dbh->prepare("select * from TABLENAME :name order by id");
$statement->execute(array(':name' => $addQuery));
$row = $statement->fetchAll();
return $row ;
}
}
?>
now when i am using this function in my PHP file like this
<?php
$objCMS=new cms();
$getCMS=$objCMS->get_rec(1);
echo $getCMS[0];
?>
i got following out put
Connected.
Fatal error: Call to a member function prepare() on a non-object in /Applications/XAMPP/xamppfiles/htdocs
i am trying to sort this out from last 2 days but no success.
i am new to PDO and want to use it.
Thanks

You $dbh is declared in the base class but without a specific scope I think it's going to default to 'private'. Hence not visible in the sub class.
Also you aren't calling the constructor. Add a call to 'parent::__construct()' in your sub class. http://php.net/manual/en/language.oop5.decon.php

You are going in wrong direction about solving this one.
If you want to give some object access to database, then that object needs access to database object that provides methods to interact with the database. You got that right.
But, inheritance is "IS A" relationship. And your CMS object is not a database type of object, and doesn't have same function as database object right? CMS object should just use Database and this is called composition. This relationship is also called "HAS A" relationship.
So instead of using Inheritance here, you should use Composition like this:
class CMS
{
protected $db;
// other CMS related stuff
}
$db = new PDO($dsn, $username, $password, $options);
$cms = new User($db);
This way your CMS can use database without using inheritance.
Google about composition vs. inheritance and when to use it.
Also take a look at this answer here:
PHP Mysqli Extension Warning
And read this article and go through examples to understand why
composition is a way to go when providing some class a way to
interact with database.
I know this is not an answer to your question, but you have gone in the wrong direction to solve your problems. I see lots of people use only inheritance so just be aware that there is much more then inheritance to make your objects interact. And in this situation, its just wrong to use Inheritance since your CMS object has nothing to do with Database, they are not the same "type". CMS should only use Database.
Hope this helps!

You need to call dbClass() in your constructor for cms
add this to the cms class
function cms() {
parent::dbClass();
}
and change get_rec to have:
$statement = $this->dbh->prepare("select * from TABLENAME :name order by id");
when using $dbh you need to reference it as $this->dbh
You need to make the $dbh to $this->dbh changes in you need to update connect_PDO() also

Related

Accessing a local variable in PHP [duplicate]

This question already has answers here:
What does the variable $this mean in PHP?
(11 answers)
Closed 3 years ago.
I have this code:
class database{
var $conn;
function connect($server,$host_username,$host_password,$host_database){
$server = 'localhost';
$host_username = 'root';
$host_password = '';
$host_database = 'e-vent system db';
$conn= new mysqli($server,$host_username,$host_password,$host_database);
if ($conn->connect_error){
die("db connection error:". $conn->connect_error);
}
}
function read_db($table,$condition){
$read="SELECT * FROM ".$table." ".$condition;
$read_result=$conn->query($read);
if(!$read_result){
echo "select error:". mysqli_error($conn);
}
return $result;
}
}
And I get this error:
Notice: Undefined variable: conn in C:\xampp\htdocs\E-vent\database.php on line 19
How can I make the $conn variable visible to the read_db function?
Change this line:
if ($conn->connect_error){
to
if ($this->conn->connect_error){
means replace all:
$conn->query
to
$this->conn->query
Explanation: If you want to use a variable in the entire class scope then you have to use the class variable instead of local (function) scope variable. In this line:
$conn->connect_error
the $conn is a local variable whose scope is limited to the function only, but when you use $this->conn, it means you are referring to the class variable which is accessible in all the member functions of the class.
And put all the content of connect function in the class constructor so that this connection is initialized at the time of class initialization. (Thanks #Magnus for pointing this)
Have a look on the variable scope, it will help you to understand the concept.
You are using class variable into a function, it's basic rule of oops that to use class variable we must access it using object. so class variable can be used under same class using $this.
so your code must be:
$this->$conn->connect_error
Instead of
$conn->connect_error
You need to make the connection object a property of the class, using $this - specifically, $this->conn. Assign your connection-object to that property. You then need to reference $this->conn everywhere else within that class, instead of using $conn.
class database {
public $conn;
public function connect($server, $host_username, $host_password, $host_database)
{
$server = 'localhost';
$host_username = 'root';
$host_password = '';
$host_database = 'e-vent system db';
$this->conn = new mysqli($server, $host_username, $host_password, $host_database);
if ($this->conn->connect_error) {
die("db connection error:". $this->conn->connect_error);
}
}
public function read_db($table, $condition)
{
$read = "SELECT * FROM ".$table." ".$condition;
$read_result = $this->conn->query($read);
if (!$read_result) {
echo "select error:". mysqli_error($this->conn);
}
return $result;
}
}
That being said, a couple of things to note,
You are not using parameterized queries, and are injecting variables directly into the query -- this is not secure, and you should use a prepared statement with placeholders.
The connect() method takes in all the arguments, but you still overwrite them in the function. Alternatives are to remove the arguments, remove the hard-coded values, or use the hard-coded values if the argument is empty.
You should not return errors to the user while in production. During development, this is fine - but in production, hide them, log them and display something generic to the user instead (like a 500 page, or some other error page).
You should specify if your properties and methods are public, protected, static or private.
Better to use public access modifier without using var. What does PHP keyword 'var' do?.
Class properties must be defined as public, private, or protected. If declared using var, the property will be defined as public.
And also The PHP 4 method of declaring a variable with the var keyword is still supported for compatibility reasons (as a synonym for the public keyword). In PHP 5 before 5.1.3, its usage would generate an E_STRICT warning.
PHP variables - http://php.net/manual/en/language.variables.variable.php
Need to change as follows
class database{
public $conn
And here
$this->conn= new mysqli($server,$host_username,$host_password,$host_database);
And here
if ($this->conn->connect_error){
die("db connection error:". $this->conn->connect_error);
}
And here as well
$read_result=$this->conn->query($read);

PHP Fatal error: Call to undefined method mysqli::mysqli_fetch_all()

hoping someone can help me, I am having the following error, looked online and tried a load of things but can't seem to figure it out, error:
Fatal error: Call to undefined method mysqli::mysqli_fetch_all() in C:\xampp\htdocs\cyberglide\core-class.php on line 38
heres my code:
<?php
class Core {
function db_connect() {
global $db_username;
global $db_password;
global $db_host;
global $db_database;
static $conn;
$conn = new mysqli($db_host, $db_username, $db_password, $db_database);
if ($conn->connect_error) {
return '<h1>'."Opps there seems to be a problem!".'</h1>'.'<p>'."Your Config file is not setup correctly.".'</p>';
}
return $conn;
}
function db_content() {
//this requires a get, update and delete sections, before its complete
$conn = $this->db_connect();
if(mysqli_connect_errno()){
echo mysqli_connect_error();
}
$query = "SELECT * FROM content";
// Escape Query
$query = $conn->real_escape_string($query);
// Execute Query
if($result = $conn->query($query)){
// Cycle through results
while($row = $conn->mysqli_fetch_all()){
//echo $row->column;
}
}
}
}
$core = new Core();
?>
I am trying to create a db_connect function, which I want to be able to call anywhere on the site that needs a database connection, I am trying to call that function on a function within the same class, I want it to grab and display the results from the database. I am running PHP 5.4.7, I am calling the database on a blank php file which includes a require to include the class file, then using this at the moment $core->db_content(); to test the function. I am building this application from scratch, running from MySQLi guides (not used MySQLi before, used to use normal MySQL query's) so if I am doing anything wrong please let me know, thanks everyone.
mysqli_fetch_all is a method of a mysqli_result, not mysqli.
So presumably it should be $result->fetch_all()
References:
http://php.net/manual/en/mysqli-result.fetch-all.php
Important: keep in mind mysqli_result::fetch_all returns the whole result set not a row as you assume in your code
There are three problems I see here.
while($row = $conn->mysqli_fetch_all()){
The method name is fetch_all() when used in the OOP way.
fetch_all() should be used with the $result object
fetch_all() is only available when the mysqlnd driver is installed - it frequently is not.
Reference
Only $result has that method. If you want to use it in a while loop use fetch_assoc(). fetch_all() returns an associative array with all the data already.
while($row = $result->fetch_assoc()){
}
thanks all, its working fine now, i had it as while($row = $conn->fetch_assoc()){
} before and changed to what i put above, but dident see it should of been $result instead of $conn, thanks for pointing that out.

What's the typical way to tie in OOP PHP with a MySQLi object?

I've been using PHP procedurally for years, but I've decided to really get with the times and start practicing OOP.
Suppose I have something like the following:
<?php
$db = new mysqli(host, user, pass, db);
class user {
public $username;
public function __construct($ID) {
$sql_query = "SELECT `username` FROM `users` WHERE `userid`='$ID'";
// execute that query somehow, store result in $result.
$this->username = $result;
}
}
$some_user = new user(1);
(I know that query needs to be escaped etc, I'm just trying to give a basic example)
My main question is what's the best way to interact with the $db object within a class? I would call $db->query($sql_query); but $db is not accessible. A lot of Googling hasn't given me a solid answer, but I've seen a lot of suggestions to pass in the $db object into the constructer, like:
$some_user = new user(1, $db);
Am I right in understanding this as "Data Injection"? It seems like there must be a better way than to explicitly include it in every single constructor. Of course I could always create $db within each class but repeatedly connecting to the database also seems unnecessary.
//this seems to happen in the global scope, so $db isn't accessible in class user yet
$db = new mysqli(host, user, pass, db);
class user {
public $username;
//to make global $db accessible, pass a reference to user's constructor:
public function __construct($ID,&$db) {
$sql_query = "SELECT `username` FROM `users` WHERE `userid`='$ID'";
// execute that query somehow, store result in $result
// if you exec the query, first you get a mysqli result *OBJECT*:
$result_obj = $db -> query($sql_query);
// next you pull out the row out of this object as an associative array:
$row = $result_obj -> fetch_assoc();
//finally you assign the retrieved value as a property of your user:
$this->username = $row['username'];
}
}
//be careful NOT to pass a reference here!!
$some_user = new user(1,$db); // NO ampersand here! passing by ref is deprecated!

optimize connections to mysql

i have a php site
in index file include connect to db function :
function connect(){
mysql_connect("localhost", "user", "pass") or die(mysql_error());
mysql_select_db("database");
}
and i use this function in everywhere i need connection
for example:
<?php
connect();
$lastnews_sql = mysql_query("SELECT text,time FROM small WHERE active='0' ORDER BY time DESC LIMIT 10");
if(mysql_num_rows($lastnews_sql)) {
while($Result123 = mysql_fetch_object($lastnews_sql)) {
?>
and use this selection:
text; ?>
in end of using :
<?php
}
}
mysql_close();
?>
there are more than 10 connect(); and mysql_close(); in index file
so there are too many connection error in index file
how can i optimize this metod ?
A singleton pattern seems to suit this down to the ground.
class Database
{
private static $instance;
public function getInstance()
{
if(self::$instance == null)
{
// Create a connection to the database.
// NOTE: Use PDO or mysqli. mysql is deprecated.
}
return self::$instance;
}
}
Use
In your classes, instead of calling connect, assuming you're using a PDO object, you could do something like:
$db = Database::getInstance();
$statement = $db->prepare("SELECT * FROM tblName WHERE val = :val");
$statement->bindParam(":val", $value);
$statement->execute();
$result = $statement->fetchAll();
Why this pattern ?
A Singleton pattern has the advantage of only having one instance of itself exist at one time. That means that you will only ever create one connection to the database.
Setting this up
Okay, so the first thing you want to do is to make a new file, let's call it Database.php. Inside Database.php, you want to pretty much write the code that I've written, only do NOT use mysql_*. Have a look at the PDO tutorial that I have provided, on how to connect to a database using a PDO object, and then you put that connection code inside the if statement, so it might look something like:
if(self::$instance == null)
{
self::$instance = new PDO('mssql:host=sqlserver;dbname=database', 'username', 'password');
}
Then, to use it in another class, put a require statement at the top. Something like:
require_once('Database.php');
Finally, look at the code I put in the use section, above. That is how you use it in your class.
Useful links
PDO Tutorial : http://php.net/manual/en/book.pdo.php
Singleton Pattern : http://www.oodesign.com/singleton-pattern.html

how to connect to another db with doctrine on zend framework

I use Zend Framework 1.10 with integration on Doctrine 1.2.
in the application.ini file, i declare the 'dsn' to connect to database.
in my application i need to connect to another db to run some queries.
how can i do it ?
i only need to run query , i don't want to generate all the Models for this DB.
right now in the bootstrap.php i do the default connection :
protected function _initDoctrine()
{
$this->getApplication()->getAutoloader()
->pushAutoloader(array('Doctrine', 'autoload'));
spl_autoload_register(array('Doctrine', 'modelsAutoload'));
$doctrineConfig = $this->getOption('doctrine');
$manager = Doctrine_Manager::getInstance();
$manager->setAttribute(Doctrine::ATTR_AUTO_ACCESSOR_OVERRIDE, true);
$manager->setAttribute(
Doctrine::ATTR_MODEL_LOADING,
$doctrineConfig['model_autoloading']
);
Doctrine_Core::loadModels($doctrineConfig['models_path']);
$conn = Doctrine_Manager::connection($doctrineConfig['dsn'],'doctrine');
$conn->setAttribute(Doctrine::ATTR_USE_NATIVE_ENUM, true);
Doctrine_Core::generateModelsFromDb('models', array('doctrine'), array('generateTableClasses' => true));
return $conn;
}
You can also store Doctrine instances in Zend_Registry and retrieve the one you are wanting later.
$conn1 = Doctrine_Manager::connection(...);
Zend_Registry::set('conn1',$conn1);
$conn2 = Doctrine_Manager::connection(...);
Zend_Registry::set('conn2',$conn2);
Then later you can retrieve it by doing the following:
$conn1 = Zend_Registry::get('conn1');
$conn2 = Zend_Registry::get('conn2');
This assumes regular Doctrine without the use of Zend or alike!
It is already there in your code, you just need to add another line with your connection. I suggest http://www.doctrine-project.org/projects/orm/1.2/docs/manual/connections/en as a good read since it deals extensively with this problem. To get an better idea what I am talking about:
$conn = Doctrine_Manager::connection($doctrineConfig['dsn'],'doctrine');
This is a connection with the name doctrine, to make a second connection, simply create another connection with another name like
Doctrine_Manager::connection($doctrineConfig['dsn'],'second_connection');
Now you have two connections, your already known doctrine and the newly created second_connection.
Read the link from above to see how to handle the retrieval of differen connections. When querying the models, you can define what connection you want to use as an optional parameter.
Just add another dsn for your other DB, and connect to that one using PDO...
As a matter of fact, we defined our databases in the Zend config as follows (using XML), to cater for multiple DB connections :
<databases>
<db_one>
<adapter>pdo_mysql</adapter>
<params>
<dbname>...</dbname>
<username>...</username>
<password>...</password>
<host>...</host>
<port>...</port>
</params>
</db_one>
<db_two>
<adapter>pdo_mysql</adapter>
<params>
<dbname>...</dbname>
<username>...</username>
<password>...</password>
<host>...</host>
<port>...</port>
</params>
</db_two>
</databases>
(Of course they're not really called db_one and db_two, but have a proper name :p).
edit
You could initialize the DB connections as follows (call this somewhere in your bootstrap) :
private function initDb()
{
foreach ($this->config->databases as $name => $database) {
try {
$db = Zend_Db::factory($database);
// Hack for MySQL utf8 encoding...
if ($database->adapter == 'pdo_mysql') {
$db->getConnection();
$db->query('SET NAMES utf8');
}
Zend_Registry::set($name, $db);
} catch (Zend_Db_Adapter_Exception $e) {
throw new Application_Exception($e->getMessage());
} catch (Zend_Exception $e) {
throw new Application_Exception($e->getMessage());
}
}
}
Then, if you want to perform a query on db_two anywhere in your code, you can use :
$db = Zend_Registry::get('db_two');
$stmt = $db->query('select ... from ...');
And use fetch() or fetchAll() on $stmt as you see fit.
BTW You don't have to use Zend_Registry and open all connections on every request of course, so just consider this as an example implementation, not as a guideline on how to solve your problem.

Categories