I currently have a class called Connect with the following code:
class Connect
{
public $sqlHost='host';
public $sqlUser='user';
public $sqlPass='pass';
public $sqlDB='db';
public $db;
public function __construct() {
$this->db = new mysqli($this->sqlHost, $this->sqlUser, $this->sqlPass, $this>sqlDB);
}
}
?>
I also have a class called TODO and I was wondering, how could I go about calling $db located in the Connect class from the TODO class?
imagine you have have two objects called
$connect = new Connect();
$todo = new TODO();
now 1 of 3 things can happen, You can pass the $connect object into a method of $todo or if a Connect object is a member of a TODO object, or create a new connect object.
scenario 1:
class TODO {
public function foo($connect){
// You can get the db object here:
$connect->db
}
}
$todo->foo($connect)
scenario 2:
class TODO {
public $connect;
public function __construct(){
$this->connect=new Connect();
}
public function foo(){
//get db:
$this->connect->db;
}
}
$todo->foo();
scenario 3:
class TODO {
public function foo(){
$connect = new Connect();
$connect->db;
}
}
I'm not sure what you want, but I think its this
$connectInstance = new Connect();
$connectInstance->db...
This way you can access the db variable in a connect object. But first, you have to instanciate the object.
Related
I recently started to update my Api code on an Apache server by using more inheritance. As I was a bit careful to use it in the past due to inexperience.
The thing is I noticed that for each Model instance a new database connection is set. So I created an alternative connection on a Static variable to pass to each Model. My question is will multiple database connection on each new Model instance cause problems if I create a connection such in my example below using __construct?
class ApiEnterprises {
protected $db;
private $table;
public function __construct(){
$this->messager = new Messager();
$this->table = 'enterprisetable';
$this->db = new \mysqli(DB_HOST, DB_USERRW, DB_PASSWRW, DB_DBASE);
if ($this->db === NULL || !$this->db) {
// set response code
echo $this->messager->databaseFailed();
}
}
}
class ApiUsers {
protected $db;
private $table;
public function __construct(){
$this->messager = new Messager();
$this->table = 'usertable';
$this->db = new \mysqli(DB_HOST, DB_USERRW, DB_PASSWRW, DB_DBASE);
if ($this->db === NULL || !$this->db) {
// set response code
$this->messager->databaseFailed();
}
}
}
Alternatively will a Static variable be safer? As I can remove it in the Controller __destruct method.
class Database {
static $connect;
protected static function conn() {
self::$connect = new \mysqli(DB_HOST, DB_USERRW, DB_PASSWRW, DB_DBASE);
return self::$connect;
}
}
class ApiUserController extends Database {
private $user_model;
private $enterprise_model;
public $connection;
public function __construct($data){
$this->connection = parent::conn();
//pass connection to models
$this->user_model = new ApiUsers($this->connection);
$this->enterprise_model = new ApiEnterprises($this->connection);
}
}
What you need is IoC container, but before you get there you need to design your models in a such a way that they accept the database instance as a parameter in the constructor. This is called dependency injection. All dependant instances are injected into the new object at the time of instantiation.
Since your Database is useless I would not recommend to use it, but you should write some database abstraction library or use one that is already available on the web. e.g. EasyDB
Here is an example of a single dependency injection:
class ApiEnterprises {
protected $db;
protected $messager;
private $table = 'enterprisetable';
public function __construct(mysqli $db, Messager $messager) {
$this->db = $db;
$this->messager = $messager;
}
}
// mysqli connection somewhere at the start of your application
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new \mysqli(DB_HOST, DB_USERRW, DB_PASSWRW, DB_DBASE);
$mysqli->set_charset('utf8mb4'); // always set the charset
// instantiate the model and pass mysqli as an argument
$enterprise = new ApiEnterprises($mysqli, $messager);
I once used to have my database connection in a file and included it on the pages that I needed it. Inside of this file, I also extended the PDO class with a new method, run(), which allows me to write shorthand PDO queries and worked fine:
class MyPDO extends PDO {
public function run($sql, $bind = NULL) {
$stmt = $this->prepare($sql);
$stmt->execute($bind);
return $stmt;
}
}
$conn = new MyPDO("mysql:charset=utf8;host=$host;dbname=$name", $user, $pass);
I'm now trying to neaten up my files and the code within them, by using classes. So, this database connection file became two classes:
class MyPDO extends PDO {
public function run($sql, $bind = NULL) {
$stmt = $this->prepare($sql);
$stmt->execute($bind);
return $stmt;
}
}
class Connection {
private $_config = NULL;
public $conn = NULL;
public $error = NULL;
public function __construct(array $config) {
$this->_config = $config;
$this->getPDOConnection();
}
private function getPDOConnection() {
if ($this->conn == NULL) {
$this->conn = new MyPDO("mysql:charset=utf8; host=".$this->_config['host']."; dbname=".$this->_config['name']."", $this->_config['user'], $this->_config['pass']);
[...]
}
}
[...]
}
At this point in time, I'm not using an autoload function to load the classes. There are only two classes needed for this particular file, so I'm requiring them manually. I'm also led to believe that including the connection class manually, allows the PDO class to be extended with MyPDO.
require API_ROOT . 'core/database/connection.class.php';
require API_ROOT . 'core/users/user.class.php';
I've tested the connection and it has indeed connected.
The problem I'm having, is using the new MyPDO method named run() inside of another class, in this case user.class.
Inside of user.class, I'm simply trying to authenticate a user and therefore need to use the run() method.
I call the user class like this:
$db = new Connection($config['database']);
$user = new User($db, $config);
And inside of the user.class, I want to use run() and do so by calling $this->db->run:
class User {
private $db = NULL;
private $config = NULL;
public function __construct($db = NULL, $config = NULL) {
$this->db = $db;
$this->config = $config;
}
public function login($email = '', $password = '', $remember_me = '') {
$user_profile = $this->db->run(" <--------------
[...]
", [$email])->fetch(PDO::FETCH_ASSOC);
}
}
But I receive the following error when I run this:
Uncaught Error: Call to undefined method Connection::run()
I understand what the error means, that there is no method called run() inside of my connection class but why does it think that method is in there? What am I doing wrong here?
#Quasimodo'sclone is correct, you need to fetch it from the conn variable as they demonstrated. If it's not working, you are doing something wrong on the implementation elsewhere because run() is a method of conn because conn is the class MyPDO which defines the run() method:
$this->db equals class Connection which creates instance of MyPDO in the __construct() and assigns it to $this->conn in the getPDOConnection() method – therefore $this->db->conn->run() is what you are looking for.
Your getPDOConnection() should maybe be renamed to setPDOConnection() then have the getPDOConnection() retrieve $this->conn:
public function getPDOConnection()
{
return $this->conn;
}
Then your User class would actually use:
$this->db->getPDOConnection()->run(...etc);
It would make it a little clearer.
I'm starting to learn how to use OOP within PHP and so far I want to create a Database class that looks like this:
class Database{
//Database connection variables
private $DBHost = "localhost";
private $DBUser = "username";
private $DBPass = "password";
private $DBName = "database3";
public $DBCon;
public function __construct(){
$this->DBCon = new mysqli($this->DBHost,$this->DBUser,$this->DBPass,$this->DBName);
}
public function con(){
return $this->DBCon;
}
public function __destruct(){
$this->DBCon->close();
}
}
And I'm trying to interact with that class from another one called Application:
include('Database.php');
class Application{
public $DB;
public function __construct() {
$DB = new Database();
}
public function InsertName($Username){
var_dump($this->DB->con());
if($this->DB->con()->query("INSERT INTO Test (name) VALUES ($Username);") === TRUE){
echo "Okay";
}else{
echo "Error";
}
}
}
But I get the error Call to a member function con() on a non-object
As a side note, is this an appropriate way to interact with a database in OOP?
Inside the Application class constructor, $DB is being assigned new Database().
This variable is considered a local variable in this case with its scope being the constructor function itself.
To properly assign the new database object to the public $DB property, you will need to access it via the object's $this reference.
public function __construct() {
$this->DB = new Database();
}
This way you will be able to access the proper assigned public property throughout your remaining class methods.
I've 3 class (Mysqliconn, Users and News).
Mysqliconn.class
Class Mysqliconn {
..connect to db
}
News.class
class News {
private $db;
public function __construct( Mysqliconn $db ) {
$this->db = $db;
}
public test() {
do something...
}
}
Users.class
class Users {
private $db;
public function __construct( Mysqliconn $db ) {
$this->db = $db;
}
public test2() {
do something...
}
}
In my php page
$db = new Mysqliconn();
$nw = new News( $db );
$us = new Users( $db )
$us->test2();
$nw->test();
My error
Catchable fatal error: Argument 1
passed to Users::__construct() must be an instance of Mysqliconn,
none given, called in ....\class\class.news.php
Now in my class Users I would like to to call a News class method,
but I get an error if I try to istantiate the class News inside class Users.
How can I do this?
Thanks.
Plz post what error you are getting. Otherwise it's difficult to capture the problem. But if you dont want to instantiate the news class in the user class you can access it like
class News
{
// news class
}
class Users
{
public function some_method(News $news){
// work with the $news object
}
}
$us = new Users();
$us->some_method(new News(/*$db*/));
This is just a basic code to give you an idea of how you can use it. In a production environment you have to take a lot of precautions.
I have db class which looks like that
class db {
protected $db;
public function __construct() {
$this->connect();
}
protected function connect() {
$this->db = new MySQLi(db_host, db_user, db_pass, db_name) or die($this->db->error);
$this->db->set_charset('utf8');
}
}
Every class inside my PHP app extends this db class
Like
class registration extends db {
var $validation;
function __construct() {
parent::__construct();
$this->validation = new validation();
...
And validation looks like that
class validation extends db {
var $ajax, $common;
function __construct() {
parent::__construct();
...
Getting error message "Too many connections". I feel that, this is not right approach: I'm every time reconnecting to db. So what's right way in your opinion? Is that possible to define('db', ...) 1 time and use everywhere inside app?
registration and validation are classes the use db but are not a sub-class of it.
Your code should look like:
$db = new DB();
$db->connect();
$registration = new Registration($db);
class Registration {
private $db;
public function __construct(DB $db) {
$this->db = $db;
...
You pass a reference to an instance of $db to all classes that require it.
The reason you're opening too many connections is probably because currently each class makes it's own connection to your database, and that is not what you want to do, or need to do.
You want to use composition here instead. Also might consider investigating Singleton pattern.
To elaborate, using composition, each class in your library will have an instance of the db class rather than be an instance of the db class.
Singleton will make the db class enforce only one instance of the class is ever created which is useful for shared resources like database connections. Have a look at this link for further reading on the topic.
http://php.net/manual/en/language.oop5.patterns.php
EDIT: Adding some code
Turning the db class into a Singleton
<?php
class db
{
static private $_oInstance = null;
protected $db;
private function __construct()
{
$this->connect();
}
static public function getInstance()
{
if(self::$_oInstance === null)
self::$_oInstance = new db();
return self::$_oInstance();
}
protected function connect()
{
$this->db = new MySQLi(db_host, db_user, db_pass, db_name) or die($this->db->error);
$this->db->set_charset('utf8');
}
}
Revising the rest of your classes to compose the db instance rather than extend the db class
class registration
{
private $_oDb;
public $validation;
function __construct()
{
parent::__construct();
$this->_oDb = db::getInstance();
$this->validation = new validation();
}
// ...
}