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']);
I am trying to find a way to get the variable called $connect to run but don't know how.
Filename: /engine/init.php
class Engine {
function MySQL() {
$connect = new PDO("mysql:host=$db_host;dbname=$db_name;charset=$db_char", $db_user, $db_pass);
}
}
Filename: /inc/database.php
require 'engine/init.php;
$engine = new Engine;
$conn = $engine->MySQL;
// Activate $connect variable
If it's not clear, please request for more info.
Thanks,
CrAzYz_
You will have to update the class to access members outside.
You have several options to do it.
1: store the connection in a public property
class Engine {
public $connection;
public function MySQL() {
$this->connection = new PDO("mysql:host=$db_host;dbname=$db_name;charset=$db_char",$db_user, $db_pass);
}
}
This way you can retrieve it by
$engine = new Engine();
$engine->MySQL();
$conn = $engine->connection;
2: Make the function return the connection
class Engine {
public function MySQL() {
return new PDO("mysql:host=$db_host;dbname=$db_name;charset=$db_char",$db_user, $db_pass);
}
}
This way your example will work (if you use Mysql as a function):
$engine = new Engine();
$conn = $engine->MySQL();
3: A more complicated but generally better aproach:
class Engine {
protected $connection;
public function __construct($db_host, $db_name, $db_user, $db_pass $db_char = "utf-8") {
$this->connection = new PDO("mysql:host=$db_host;dbname=$db_name;charset=$db_char",$db_user, $db_pass);
}
public function MySQL() {
if ( !$this->connection instanceof PDO ) {
throw new Exception("Connection is not set up");
}
return $this->connection;
}
}
This would work almost as you wanted, except you cant access the connection directly (its protected), but only through the MySql function. This way if you forgot to init the connection an exception is thrown.
$engine = new Engine("localhost", "db_name", "user", "pass");
$conn = $engine->MySQL(); // you don't even need to save the connection to a local variable, because the function only references the connection and won't start a new one
Footnote:
If you had to as this kind of question you should probably look up and learn more about OOP. For php this is a start: http://php.net/manual/en/language.oop5.php
About to run off so this is a little quickly done.
class Engine
{
public $db;
public function connect($host, $database, $charset, $user, $pass)
{
$this->db = new PDO("mysql:host=$host;dbname=$database;charset=$charset", $user, $pass);
}
}
First of we have your Engine class that you want to create, we've created a property named db on the class that we can access with ->db. We also have a method called connect which we pass our database variables into so that PDO can connect to our database.
Now we pass in our database credentials to our connect method, in a production environment I really would advise against hard coding these and instead use something like environment variables.
$engine = new Engine();
$engine->connect('127.0.0.1', 'example_database', 'UTF-8', 'root', 'root');
We can then use our newly initiated PDO connection like so:
$statement = $engine->db->query('SELECT * FROM some_table');
$result = $statement->execute();
That should at least give you a starting point, there are other ways to go about this but I didn't want to stray too far from your original code.
Also if anyone spots anything wrong, let me know and i'll update it when I'm back in, need to run off in a sec.
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
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