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']);
Related
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']);
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']);
Ok,
This is sort of an involved problem, but any help or advice would be incredibly appreciated.
So I'm working with a site that (using .htaccess) redirects all traffic to a load.php. For any sql functionality, I have an abstract class that has a lot of query statements as functions that pass parameters to define the specifics of each query.
e.g.
$table->update("constraints")
I'm trying to figure out how to set the connection to the database on load.php, and then set the connection as a variable ($mysqli) that can then be referenced in my abstract query class without having to pass the parameter to every single query function call.
Again, any help or advice would be appreciated.
Here's an example of a function:
function clearTable (){
$mysqli = dbConnect::connect();
$sql = "TRUNCATE TABLE $this->tablename";
$mysqli->query($sql);
}
If I connect to the database in a construct function and set $this->mysqli and replace $mysqli = dbConnect::connect(); with $mysqli = $this->mysqli, none of the queries work. Though they work with a fresh reconnect on each call.
You should use Dependency Injection for this.
Basically it means that the class that needs the database connection doesn't create the connection, it just receives the already instasiated instance.
Example
In some init file:
// Create the db connection
$db = new Mysqli(......);
// Pass it to the query class that needs it
$queryClass = new QueryClass($db);
Then in your class file:
class QueryClass
{
protected $db;
public function __construct($db)
{
// $this->db will now be the same Mysql instance
$this->db = $db;
}
public function doSomeQuery()
{
$this->db->query(....);
}
}
A bonus for this is that you don't need to touch the QueryClass, if you ever want to start making some unit tests. You only need to pass a DB connection to a test database instead.
After looking through this a bit more, I can also create my db::connect() function to look like this:
class dbConnect {
private static $db;
private $mysqli;
private function __construct() {
$this->mysqli = new mysqli(HOST, USER, PASSWORD, DATABASE);
}
function __destruct() {
$this->mysqli->close();
}
public static function connect() {
if (self::$db == null) {
self::$db = new dbConnect();
}
return self::$db->mysqli;
}
}
and pass that as $this->mysqli in the query functions file
Sorry for the stupid question am a newbie to oop in php...i have a proble wiriting a mysqli class thet returns a connection handler that enable me the connection handler in other classes/methods. i run a small procedural blog n wanted to convert to oop.
heres a my working code example. please refactor for me where necessary. Thank in advance.
$db_link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
class myDB extends mysqli
{
public function getConfig($id, $db_link) // thanks cbuckley
{
$db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
i have defined the constants already and the connection is successful but the select is not working. on the index page this goes
include('inc/dbc.php');
$db = new MyDB();
echo $db->getConfig(1, $db_link);
any help is appreciated
Your question is not very specific, and I have the feeling you're not really aware what your concrete problems are. You've already accept an answer that gives you some code but puts you in the wrong direction as it does not solve your underlying problem and wastes code.
The first thing you should know if you want to make use and benefit of the object oriented interface of PHP's mysqli extension is, that the Mysqli class represents the database connection (the "link" as it was named for a procedural approach) already:
require('inc/dbc.php');
$dbConnection = new Mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
That's already it. Sure you might want to use some error handling here:
if ($dbConnection->connect_error)
{
throw new Exception(
sprintf('(#%d) %s', $dbConnection->connect_errorno,
$dbConnection->connect_error)
);
}
Throwing exception instead of let's say die('message') is done, because you can easily create an exception handler so that you can display a more useful response to the user from within a central place instead of handling each exceptional error-case where it appears (actually at the place where die would be).
You can also log and mail the backtrace so you can fix things more easily. Naturally you do not need to use exceptions, however the rule of thumb is to use die only in scripts you throw away in let's say a week and it does not work well with object oriented design.
As you will need this code anyway in all places where you will need your database connection, you can create your own connection object to bring those parts together as they belong together:
class DatabaseException extends Exception
{
}
class DatabaseConnection extends Mysqli
{
public function __construct($host, $user, $password, $database = "", $port = NULL, $socket = NULL) {
parent::__construct($host, $user, $password, $database, $port, $socket);
$this->throwConnectionExceptionOnConnectionError();
}
private function throwConnectionExceptionOnConnectionError() {
if (!$this->connect_error) return;
$message = sprintf('(%s) %s', $this->connect_errno, $this->connect_error);
throw new DatabaseException($message);
}
}
The usage is actually pretty straight forward and very much the same, only the name of the class varies and it's definition needs to be loaded:
require('inc/dbc.php');
require('inc/database.php');
$dbConnection = new DatabaseConnection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
As written, the connection object already represents your database connection. So every part in your application that needs it, has to ask for it. Let's review your example function:
function getOption($id, $db_link)
{
// $db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
I renamed the function and I commented the first line, even this might be what you want. Actually, if that function would be part of the DatabaseConnection object, it could work like this:
class DatabaseConnection extends Mysqli
{
...
public function getOption($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
As this example demonstrates, the database connection is already there. However, this is not advisable. Imagine you not only have options but this and that and such and what not more. You would create one function after the other all in one class. Well for a little application that might even so work right, but imagine more and more. You would get one very large class that is responsible for many things. So it would be bad to do this, even if you can use $this already to prepare the statement.
Also take note that you should prepare statements. This has been answered here numerous times, if you're not used to it, read about it, it's worth the lines. There are better ways to not repeat code (DRY: Don't repeat yourself) while stepping into object oriented (you should even already do this with procedural).
So as to have this all in one class would be a problem, you instead put it in a class of it's own:
class DatabaseModelBase
{
protected $connection;
public function __construct(Connection $connection) {
$this->connection = $connection;
}
protected function prepare($query) {
$connection = $this->connection;
$statement = $connection->prepare($query);
if (!$statement) {
throw new DatabaseException(
sprintf('(%s) %s', $connection->error, $connection->errno)
);
}
return $statement;
}
}
class Option extends DatabaseModelBase
{
public function find($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
}
This has some extended error handling again, because most often mistakes are made in the SQL query. And as you can see the individual function to fetch some specific data is placed in it's own class. You can use such classes to group the fetching and updating for specific datatypes.
Usage in full:
$dbConnection = new Connection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$option = new Option($dbConnection);
$optionValue = $option->find(1);
echo $optionValue; # value for option with ID1
The names of the Option object probably is not well, I tried to keep the example lightweight but also offer some separation. For other scenarious you might want to prefer some different kind how to access the db connection, because it is injected into Option via it's constructor, Option does not deal any longer with the details how the database connection is being created.
For example you can make the database connection object more smart only to connect to the database the first time prepare or query is actually used with it. So that requests to your website that do not need a database connection would not needlessly connect to the database.
You find more examples in other questions and you might want to learn about dependency injection. Also you always want to keep things apart from each other, so you have some objects that are only lightly connected to each other.
How to successfully rewrite old mysql-php code with deprecated mysql_* functions?
Dependency Injection simple implementation
I would suggest moving the connect to the database also inside the class:
class myDB extends mysqli
{
private $link;
public function Connect()
{
$this->link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
}
public function getConfig($id) // thanks cbuckley
{
$res = mysqli_query($this->link,"SELECT * from config where id='$id'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
And use it like this:
include('inc/dbc.php');
$db = new MyDB();
$db->Connect();
echo $db->getConfig(1);
I recommend you to Wrap the mysqli class in a new Class instead extending it:
For those Classes, where you need the Configuration, just include the Configuration with Dependency Injection. This brings you the Benefit, that the Code, where you need the Configuration, don't need to know about the Way, Configuration get its values.
If you later decide to parse Configuration from a iniFile, you only need to change the Configuration-Class or even better, write a new Class which implements ConfigurationInterface and inject the new ConfigurationClass.
class Configuration implements ConfigurationInterface{
private $mysqli;
public function construct(mysqli $mysqli) {
$this->mysqli = $mysqli;
}
public function get($key)
{
// You should escape this query to prevent SQL-injection
$res = $this->mysqli->query("SELECT * from config where id='$key'");
$row = $res>fetch_array();
return $row['option'];
}
}
interface ConfigurationInterface {
public get($key);
}
Use it like this:
$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);
var_dump($config->get(0));
I'm kinda new to PDO with MYSQL, here are my two files:
I have a connection class that I use to connect to the database:
class connection{
private $host = 'localhost';
private $dbname = 'devac';
private $username = 'root';
private $password ='';
public $con = '';
function __construct(){
$this->connect();
}
function connect(){
try{
$this->con = new PDO("mysql:host=$this->host;dbname=$this->dbname",$this->username, $this->password);
$this->con->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
echo 'We\'re sorry but there was an error while trying to connect to the database';
file_put_contents('connection.errors.txt', $e->getMessage().PHP_EOL,FILE_APPEND);
}
}
}
I have an account_info class that i use to query the data from the database:
class account_info{
function getAccountInfo(){
$acc_info = $this->con->prepare("SELECT * FROM account_info");
$acc_info->execute();
$results = $acc_info->fetchAll(PDO::FETCH_OBJ);
foreach ($results as $key) {
$results->owner_firstname;
}
}
}
I include both these files in my index.php page:
include_once 'classes/connection.class.php';
include_once 'classes/accountinfo.class.php';
$con = new connection();
$info = new account_info();
$info->getAccountInfo();
I just cant get it to work I'm not getting any output, I think it has something to do with the scope, but I don't know the correct why to fix it as I'm new to this PDO and OOP stuff.
Thanks in advance.
Solution 1
Replace class account_info { with class account_info extends connection {
Replace
$con = new connection();
$info = new account_info();
with
$info = new account_info();
and it should work.
Solution 2 (suggested)
I highly suggest you to solve your problem with dependency injection in this case.
Just replace your account class with:
class account_info {
private $con;
public function __construct(connection $con) {
$this->con = $con->con;
}
public function getAccountInfo(){
$acc_info = $this->con->prepare("SELECT * FROM account_info");
$acc_info->execute();
$results = $acc_info->fetchAll(PDO::FETCH_OBJ);
foreach ($results as $key) {
$results->owner_firstname;
}
}
}
and use it in index.php like this:
include_once 'classes/connection.class.php';
include_once 'classes/accountinfo.class.php';
$con = new connection();
$info = new account_info($con);
$info->getAccountInfo();
Explanation
As a general good rule: always specify the scope keyword for functions (public, protected or private).
The first solution is called inheritance and what we basically did was extending the account class with the connection class in order to inherit all the methods and properties from the connection class and easily use them. In this case you have to watch out for naming conflicts. I suggest you to take a look at the class inheritance in the PHP manual.
The second solution is called dependency injection and it is a wildly encouraged design pattern that makes your classes accept other classes in their constructor in order to explicitly define the class dependency tree (in this case account depend from connection and without the connection we can't make account work).
Another, of thousands of possible solution, would be the one that someone posted below which is a design pattern called Singleton. However that patter has been reevaluated recently as anti-pattern and should not be used.
A common method is to use a singleton pattern in your database class.
Something like this:
class connection {
private static $hInstance;
public static function getInstance() {
if (!(self::$hInstance instanceof self)) {
self::$hInstance = new self();
}
return self::$hInstance;
}
/* your code */
}
Then, you can simply use
$database = connection::getInstance();
$database->con->prepare(....)
etc