Extending MySQLi giving me error - php

I am trying to figure out how can I extend mysqli with my classes.
This is my db class;
class db {
protected $_server = "localhost";
protected $_user = "root";
protected $_pwd = "";
protected $_db = "test";
protected $_charset = "utf8";
function __construct(){
$this->createConnection();
}
private function createConnection(){
$this->mysqli = new mysqli($this->_server, $this->_user, $this->_pwd, $this->_db);
$this->mysqli->query("SET NAMES ".$this->_charset);
$this->mysqli->query("SET CHARACTER SET ".$this->_charset);
if($this->mysqli->connect_error) {
//die('Error ('.$this->mysqli->connect_errno.') '.$this->mysqli->connect_error());
die();
}
//$this->mysqli->close();
}
public function mysqli_fetch_object($query){
$query = $this->mysqli->query($query);
return $query->fetch_object();
}
}
and I want to extend this db class in this login class:
require_once("dbClass.php");
class login extends db {
public function __construct(){
}
public function check_login($email, $password) {
$email = $this->mysqli->real_escape_string($email);
$validateMail = filter_var($email, FILTER_VALIDATE_EMAIL);
$password = $password;
$database_check = $this->mysqli_fetch_object("SELECT * FROM accounts WHERE email = '$validateMail'");
}
}
and I get these:
Notice: Undefined property: login::$mysqli
Fatal error: Call to a member function real_escape_string() on a non-object

If you override __construct, the original constructor won't run and won't create the connection.

There is no point in extending login from db.
Instead of extending you have to use database class as a service in login class.
class login{
public function __construct($db){
$this->db = $db;
}
public function check_login($email, $password) {
$stmt = $this->db->prepare("SELECT * FROM accounts WHERE email = ?");
...
}
}
Also note that your way of running queries is wrong. You have to use prepared statements

First, you use $this->mysqli, but there's no property $mysqli in the db class. Declare it as protected, since the extended class will need access to it:
protected $mysqli;
And second, you must call parent's constructor as other people said, otherwise it won't run.
But as a side note, I suggest you don't extend the db class as login. The best approach I found so far, is to have a db access class, instantiated as a singleton for your app. This way any class that needs it will ask for a singleton instance and use it.
The advantage is obvious: all your db access will occur thru a single instance, making your app much more efficient, because everything will be done thru a single database connection. The way you're doing, as soon as you construct a login instance, a new database connection will be established.
If you keep extending the db class to other classes, like users, products, and so on, new db connections will be created, wasting resources on your server.

You should remove the constructor overload, or in your constructor method you should make a call to parent::__construct. Without it, the parent's constructor is not fired.
class login extends db {
public function __construct(){
parent::__construct();
}

Related

How to use an instance of a class within another class in PHP 7

I have what seems like a simple query but I have not found an answer elsewhere.
I have 2 classes, one called DB which essentially connects to the database and can then run queries. I instantiate it at the top of the document $db= new DB; and I can then run a series of queries on the database throughout the page.
The issue I am having is that I want to use this instance within another class I have called User.
I know I can either instantiate again but this does not make sense OR pass the instance of DB when instantiating User, for instance $user = new User($db); but considering the $db instance will be used by most classes I am going to create I am thinking there is a better solution to import it into other classes.
I have looked at the global route but I read it is bad practice + I am getting unexpected global error
class User{
global $db;
public function __construct()
{
var_dump($this-> db);
}//end constructor
}//end class
Since your DB client will be instantiated once and then used everywhere else my initial thought was to recommend passing it as a constructor parameter (dependency injection), but since you are not fan of this approach, I would recommend making your DB client a singleton class, which means it can only be instantiated once and any subsequent attempt would return the same instance everywhere.
You can see a detailed response about singleton classes in PHP at Creating the Singleton design pattern in PHP5.
As a quick example, your DB would look like similar to this:
final class DB
{
public static function getInstance()
{
static $inst = null;
if ($inst === null) {
$inst = new self();
}
return $inst;
}
private function __construct()
{
// your code here ...
}
// your code here ...
}
And then, on your User class you would just get the DB class instance:
class User {
// your code here ...
public function doSomething() {
$db = DB::getInstance();
// your code here ...
}
}
PHP does not handle scopes like Javascript does, your $db is undefined.
The scope of a variable is the context within which it is defined. For the most part all PHP variables only have a single scope. This single scope spans included and required files as well […] Within user-defined functions a local function scope is introduced. Any variable used inside a function is by default limited to the local function scope.
Source: http://php.net/manual/en/language.variables.scope.php
This means that there is only a global scope and a function/method scope in PHP. So, either pass the $db instance into the method as a collaborator
class User{
public function __construct() {}
public function getInfo(Database $db) {
$db->query( /* ... */ );
}
}
$user = new User();
$db = new Database();
$user->getInfo($db);
or pass it in the constructor (dependency injection)
class User{
private $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function getInfo() {
$this->db->query( /* ... */);
}
}
$db = new Database();
$user = new User($db);
$user->getInfo();

Why does this come up as non-object?

I am trying to create a really simple database connection class in PHP, but I ran into a bit of problem.
First off, here's the code I wrote:
class db {
protected $db;
public function __construct() {
$this->db = new PDO('mysql:host=127.0.0.1;dbname=main', 'root', '');
}
}
Whenever I try to call $db from another class that extends my database class, I get an error like this one:
Fatal error: Call to a member function prepare() on a non-object in class.php
I call the database link in the other class like the following example:
class example extends db {
public function challenge_exists($challenge) {
$query = $this->db->prepare('SELECT * FROM challenges WHERE challenge = :challenge');
$query->bindParam(':challenge', $challenge, PDO::PARAM_STR);
$query->execute();
if($query->rowCount() > 0) {
return true;
}
}
}
I have no idea what I have done wrong and would appreciate any suggestions on how to make this work.
To the question, if there is a __construct() method in the child class then you need to call the __construct() of the parent class explicitly, or else it is not executed and $db is never instantiated. Though you don't show the child constructor in your example code it is safe to assume that there is one based on the behavior, so:
class example extends db {
public function __construct() {
parent::__construct();
//more stuff
}
}
If you don't need a constructor in the child class then remove it and the parent constructor will be called when you instantiate an object of the child class.
As for the design, this is bad and you should consider one database object and inject that into objects that need it or similar approach:
class example {
public function __construct($db) {
$this->db = $db;
}
}
$db = new db(); // do this once
$example = new example($db); // inject when needed
You should never extend an applications class from a database class in the first place.
User is not a database. It's a user. They have nothing in common. Database have to be used as a service by a user, not being a parent.
Not to mention that creating a hundred connections from the same script is a very bad idea.
Regarding the "accepted" answer, it's just wrong. As long as there is no constructor in the child class defined (like in the OP), then parent counstructor is used. Welcome to Stack Overfraud.

php objects interaction - calling instances within other instances

I created a simple database connection class:
class db {
private $db_host = "host";
private $db_user = "user";
private $db_pass = "pass";
private $db_name = "db_name";
public $con;
public function __construct() {
$this->con = mysqli_connect($this->db_host, ... );
...
}
public function query($query) {
return mysqli_query($this->con,$query);
}
}
Now, I would like to use $db->query() within another class instance:
class display {
public function menu() {
this function creates a list based on a result of $db->query('SQL query')
}
plus various other functions to display different things, all using $db->query()
So what is the problem?
First, I got this working by adding 'global $db' to $disply->menu() but this is obviously a big NO NO and needs to be specified within each method.
It is probably clear now that I would like to use $db->query(SQL query) wherever and whenever I need an SQL result, not just within the global scope.
I spent the last couple of hours looking this up but to my surprise most people ask how to use something like $instance->instance->method in global.
Many thanks for your time.
Tom
A simple solution is to inject the $db object when you instance your classes
class Display {
protected $db;
public function __construct($db) {
$this->db = $db;
}
public function menu() {
// here you can use $this->db as if it was the global $db;
}
}
You need to add $db as a parameter everytime you instance your classes
$mydisplay = new Display($db);
There are other ways to achieve the same purpose. For example you can make the $db class a singleton, and add a static method to retrieve the instance from wherever you need. And there are more sophisticated ways such as using pimple to manage your dependency injections as a provider instead of doing it manually.

PHP - How to access pdo object from other (multiple) classes

I am switching my MVC to use PDO (I know, overdue). My application has, in the past, used the following class hierarchy:
Database.class>Main.class>User.class
(each one extending the other). But before any object is created, the mysql connection was made (mysql_connect). Once the connection was open I could use Database.class as a wrapper class through which all my queries were performed. Through extention, a query in the User.class could be made simply by calling the "query" function ($this->query).
Using PDO, I've tried to imitate the process but find errors. I created a singleton function in the Database.class:
function __construct()
{
$this->db = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8', DB_USER, DB_PASSWORD);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
public static function getInstance()
{
if (!isset(self::$instance)){
$object = __CLASS__;
self::$instance = new $object;
}
return self::$instance;
}
function query($qry,$params=NULL){
$qry = $this->db->prepare('SELECT * FROM users WHERE userID = :userID');
$qry->execute(array(':userID' => 1));
$results = $qry->fetchAll(PDO::FETCH_ASSOC);
return $results;
}
Then in Main.class I get the instance:
function __construct()
{
$this->db = parent::getInstance();
}
So in User.class I try to call
function __construct(){
parent::__construct();
}
function test(){
return $this->db->query("test");
}
So I can run any queries fine from the Main.class object. But if I try to run queries from User.class object I get the error: "Call to a member function query() on a non-object" In other words, if User.class extends main I should be able to access the variable $db in Main from User.class (I call the constructor for Main when the User object is created). Part of the issue is that Main.class is created earlier in the application as it's own object, I believe causing two instances of PDO to be created - which is why it doesn't work through extension (through a second object that also extends the database.class)
So my question is: is there a way to make this happen? Or is my best option to use injection for every object I create (because some scripts incorporate multiple objects that extend Main.class - which try to create an instance of PDO each time) and pass the pdo object to the constructor? I'd rather not have to do that (the less markup the better) So another option would be to use a STATIC variable that all classes use? What's the best method? (let me know if this is confusing)
I've seen people using injection for this, and I've seen examples of extending the pdo wrapper class (but only once).
Thanks! (I love stack overflow!)
You dont want any of these to extend the database class because that will essentially make them all singletons of which you can only have one instance... you Want to make them USE the database class instead. So you would put you most abstract db methods on the Database and then methods that create queries for specific things would be on the User or what have you. This means your Database actually wraps PDO and is what all other classes work with for db operations. The Main or Base class may not even be needed unless you are trying to implement active record or something.
class Database {
static protected $instance;
/**
* #var PDO
*/
protected $connection;
protected function __construct($dsn, $user, $pass, $attrs = array()) {
// create pdo instance and assign to $this->pdo
}
public static function getInstance() {
if(!self::$instance) {
// get the arguments to the constructor from configuration somewhere
self::$instance = new self($dsn, $user, $pass);
}
return self::$instance;
}
// proxy calls to non-existant methods on this class to PDO instance
public function __call($method, $args) {
$callable = array($this->pdo, $method);
if(is_callable($callable)) {
return call_user_func_array($callable, $args);
}
}
}
class Main {
protected $db;
public function __construct() {
$this->db = Database::getInstance();
}
}
class User extends Main{
public function __construct() {
parent::__construct();
}
public function findById($id) {
$qry = $this->db->prepare('SELECT * FROM users WHERE userID = :userID');
$qry->execute(array(':userID' => $id));
$results = $qry->fetchAll(PDO::FETCH_ASSOC);
return $results
}
}

PHP OOP Questions, with an Example

I know there were some questions about this opened, but I need a more "specific" example and solution.
Here is my Example:
databse.class.php
class db{
public function connect($conStr){...}
}
func.class.php
func class{
public insert_song(){
//ineed to use the conenct method from database
//then I would INERT INTO...
}
}
Questions:
1) Should I require or extend the db class in func class?
2) If I require, will the scope of the db class functions will remain? (lets say if I have a private variable there, will it be accessible from the out side?)
No, you should not require or extend the database class.
No, private variables or methods never get available outside the class. Protected variables are available to child classes only, public variables are...public.
You could require the file in which the database class lives somewhere in your config, so you can instantiate the database class wherever and whenever you want. But, as you'll probably need only one instance of the database object, you could just instantiate it in the config and pass it around using Dependency injection.
This basically means that you pass the database object to other objects needing one. A common way of dealing with database objects is using Constructor injection, although setter injection would do as well.
What you do is something similar to this:
// config:
$db = new Database;
$db->setConnectionValues();
$fooClass = new Foo($db);
$fooClass->insertSomething();
// fooClass:
class Foo
{
private $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function insertSomething()
{
$this->db->query("INSERT");
}
}
This solves most of your dependency problems.
// changed the class name, func is not good for a class name.
class Foo {
protected $db;
public setDb($db) {
$this->db = $db;
}
public insert_song(){
//ineed to use the conenct method from database
//then I would INERT INTO...
$this->db->insert(...);
}
}
Example:
// omited the error handling.
$db = new db();
$db->connect();
$foo = new Foo();
$foo->setDb($db);
$foo->insert_songs();
As part of Abstraction, you should separate the responsibilities for your classes. Your Database class should care about your Songs (which is how you should name it) class.
If your Songs class uses the Database class, you should inject it in the constructor as follows:
<?php
class Database {
public function connect($conStr) {
/*
* Connect to database here
*/
}
}
class Songs {
private $db;
public function __construct(Database $db) {
$this->db = $db;
}
public function insert_song($song) {
/*
* Now you can use $this->db as your database object!
*/
}
}

Categories