Is die function accept only strings? - php

this code works:
if (isset($db->error)) {
echo $db->error;
}
This code in not working:
if (isset($db->error)) {
die($db->error);
}
This is my DB class:
class Db {
private $db,
$error;
public function __construct() {
return $this->db = new mysqli(DB_SERVER, DB_USER, DB_PASS, D_NAME);
if ($this->db->connect_error) {
$this->error = $this->db->connect_error;
}
}
}
"D_NAME" is wrong so an error appears but I didn't kill the page, content still appear after the error. Why? Thanks!

The if block in the constructor is never executed, because you are returning $this->db:
public function __construct() {
return $this->db = new mysqli(DB_SERVER, DB_USER, DB_PASS, D_NAME);
// the lines after return will never be executed!
}
This is the first reason why the $db->error is unset.
The second reason is that the $error member is private, which means that you are not allowed to access this property directly. So you should make it accessible in one of the following ways (at least):
make it public;
implement the __get and __isset magic methods;
implement a getter method.
Using public $error
class Db {
private $db;
public $error;
public function __construct() {
$this->db = new mysqli('localhost', 'sss3', 'a4J1uQzQCasD', 's3_small');
if ($this->db->connect_error) {
$this->error = $this->db->connect_error;
}
return $this->db;
}
}
$db = new Db;
if (isset($db->error)) {
die($db->error);
}
echo 'xxx', PHP_EOL;
Using __isset and __get magic methods
class Db {
private $db;
private $error;
public function __construct() {
$this->db = new mysqli('localhost', 'sss3', 'a4J1uQzQCasD', 's3_small');
if ($this->db->connect_error) {
$this->error = $this->db->connect_error;
}
return $this->db;
}
public function __get($key) {
if ($key === 'error') {
return $this->error;
}
}
public function __isset($key) {
if ($key === 'error') {
return isset($this->error);
}
}
}
$db = new Db;
if (isset($db->error)) {
die($db->error);
}
echo 'xxx', PHP_EOL;
Implementing a getter method
A getter method is just a method returning value of a private member. In our case it is $error. So you might leave it private, but add a method to access its value. For instance:
public function getError() {
return $this->error;
}

Related

Singleton pattern in my php project returns an empty object in second time

i have two classes in my project.
Db.php :
<?php
namespace app\core;
use \PDO;
class Db
{
private $dsn = 'mysql:host=localhost;dbname=test';
private $user = 'root';
private $password = '6ReA4';
private $options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];
private static $PDO = null;
private function __construct()
{
try {
self::$PDO = new \PDO($this->dsn,$this->user,$this->password, $this->options);
} catch (\PDOexception $e) {
/* Exception of datebase connection (error message in future) */
echo "Date base connection error ".$e->getMessage();
}
}
private function __clone() {}
private function __wakeup () {}
public static function conDb()
{
if (is_null(self::$PDO)) {
return new self();
} else { return self::$PDO; }
}
}
and Model.php
<?php
namespace app\core;
class Model
{
private $db;
private $db2;
public function __construct()
{
$this->db2 = Db::conDb();
$this->db = Db::conDb();
if ($this->db == $this->db2) {
echo "Singleton works";
} else { echo "Fail"; }
}
public function getById()
{
}
public function getAll()
{
}
}
private $db;
private $db2;
public function __construct()
{
$this->db2 = Db::conDb();
$this->db = Db::conDb();
if ($this->db == $this->db2) {
echo "Singleton works";
} else { echo "Fail"; }
}
public function getById()
{
}
public function getAll()
{
}
}
I'm trying to realize singleton pattern but method conDb() during the Model object creation returns an empty object a second time instead of the same one. Please help me to understand what is the problem and how can i solve this? What am i doing wrong?
The issue resides in the Db class definition. The first time you called conDb it returned a new Db object that then assigned the static variable a PDO object.
The second time you call that method you get back a PDO object which made the if guard evaluate to false, since a Db object and PDO object are different. In case you call it more than 2 times the objects returned thereafter would be PDO objects and tested for true.
Below a suggested change to the Db class.
class Db
{
private $dsn = 'mysql:host=localhost;dbname=test';
private $user = 'root';
private $password = '6ReA4';
private $options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];
private static $PDO = null;
private function __clone()
{
}
private function __wakeup()
{
}
public static function conDb()
{
// This is always null the first call
if (is_null(self::$PDO)) {
// Here you returned a new Db object.
// return new self(); // <- old line.
try {
self::$PDO = new \PDO($this->dsn, $this->user, $this->password, $this->options);
} catch (\PDOexception $e) {
"Date base connection error " . $e->getMessage();
}
}
// Here you returned a PDO object in an else, this can just be the variable after the PDO object is created.
return self::$PDO;
}
}
In the construction of the Model, the if would evaluate to false testing a Db object vs a PDO object.
public function __construct()
{
$this->db2 = Db::conDb();
$this->db = Db::conDb();
if ($this->db == $this->db2) {
echo "Singleton works";
} else {
echo "Fail";
}
}

Unable to use PDO methods when using DB class

Hey guys I'm doing this wrong again I'm sure, but I'm trying to instantiate a PDO database
handler from my class Database from the file class.database.php inside my class AdminSession
from class.admin.php, somethings a bit screwy with my dependancy injection, and it is not
allowing me to use PDO's methods corretly; like fetch(), prepare() etcetra.
the class.database.php file
class Database
{
public $db; // handle of the db connection
private static $dsn="mysql:host=server2.com;dbname=database";
private static $user="user";
private static $pass="pass";
private static $instance;
public function __construct ()
{
$this->db = new PDO(self::$dsn,self::$user,self::$pass,$self::$opts);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->db->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
switch($_SERVER['ENVIRONMENT']) {
case 'staging':
self::$dsn="mysql:host=server1.com;dbname=database";
self::$user="user";
self::$pass="pass";
break;
default:
self::$dsn="mysql:host=server2.com;dbname=database";
self::$user="user";
self::$pass="pass";
}
}
public static function getInstance()
{
if(!isset(self::$instance))
{
$object= __CLASS__;
self::$instance=new $object;
}
return self::$instance;
}
}
and here's the topmost of my class.admin.php, and a method that is throwing an error.
right now the errors I'm getting
PHP Fatal error: Call to undefined method line 230
If I use $this->db-prepare($sql)
or
PHP Fatal error: Call to a member function prepare() on a non-object line 230
If I use $db-prepare($sql)
require('library/class.database.php');
class AdminSession {
static $abs_path;
public function __construct(Database $db) {
session_start();
self::$abs_path = dirname(dirname(__FILE__));
if($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->post = $_POST; // filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
if(get_magic_quotes_gpc ()) {
//get rid of magic quotes and slashes if present
array_walk_recursive($this->post, array($this, 'stripslash_gpc'));
}
}
$this->get = $_GET; // filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
array_walk_recursive($this->get, array($this, 'urldecode'));
}
// other methods
private function checkDB($username, $password) {
$sql = "SELECT * FROM users WHERE username=:username";
try {
$db = Database::getInstance();
$stmt = $db->prepare($sql);
$stmt->bindParam("username", $username);
$stmt->execute();
$user = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
if($user) {
//general return
if(is_object($user[0]) && md5($user[0]->password) == $password) {
return true;
} else {
return false;
}
} else {
return false;
}
} catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
}
You can't put logic into your class definition. Instead, determine the value of these variables within the constructor. The switch will work in a method, but not when defining members.
Edit: I actually feel silly for missing this. The connection was made before the switch statement. I don't know that it'll fix the second set of issues ... but it'll behave properly for the original question now.
class Database
{
public $db; // handle of the db connection
private static $opts = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
private static $dsn="mysql:host=server2.com;dbname=database";
private static $user="user";
private static $pass="pass";
private static $instance;
public function __construct ()
{
switch($_SERVER['ENVIRONMENT']) {
case 'staging':
self::$dsn="mysql:host=server1.com;dbname=database";
self::$user="user";
self::$pass="pass";
break;
default:
self::$dsn="mysql:host=server2.com;dbname=database";
self::$user="user";
self::$pass="pass";
}
$this->db = new PDO(self::$dsn,self::$user,self::$pass,$self::$opts);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public static function getInstance()
{
if(!isset(self::$instance))
{
$object= __CLASS__;
self::$instance=new $object;
}
return self::$instance;
}
}

Syntax - accessing a class's property's method

I just upgraded my php form mysql to use mysqli in an object oriented approach. I have reason to believe that this code has bug in it. My goal is to use a singlton pattern to guarantee only one database connection per script execution. $db holds the database link.
Can someone verify the line
return $one->$db->query($query);
the syntax looks off.
class one
{
private static $single = NULL;
public $db = NULL;
public function __construct()
{
$this->db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DATABASE);
self::$single=1;
}
public static function make_one()
{
if(self::$single==NULL)
{
return new self();
}
}
}
/*database*/
class database
{
public function __construct()
{
one::make_one();
}
public static function arche_query($query)
{
return $one->$db->query($query);
}
}
Change it to
return one::make_one->db->query($query);
how ever your singleton pattern is not correct
A singleton pattern should create only one instance , in your case its not that case
class one
{
private static $_selfInstace;
public $db;// default is null so no need to assign
public function __construct()
{
$this->db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DATABASE);
}
public static function getInstance()
{
if( !(self::$_selfInstace instanceof self) ) {
self::$_selfInstace= new self();
}
return self::$_selfInstace;
}
}
class database
{
public function __construct()
{
}
public static function arche_query($query)
{
return one::getInstance()->db->query($query);
}
}

Error while adding PDO to my code

I have connection.php file where i am initializing PDO in the $db.
And i want to check this validation in the User.php which i include after connection.php.
but it is giving me error .
try {
$db = new PDO("mysql:dbname=$db_name;host=$db_host", $db_username,$db_password);
echo "PDO connection object created";
}
catch(PDOException $e){
echo $e->getMessage();
}
How can i validate this code by executing PDO.
How i will pass the PDO to the User Class..
Fatal error: Call to a member function query() on a non-object in /var/www/youngib/rahul/yapi/user.php on line 41
$sql="select * from users where email='$this->email'";
$rs=$db->query($sql);
if(mysql_num_rows($rs)>0){
$msg=geterrormsg(4);
//email already exist
echo $msg= "{ 'success': 'false','msg':'$msg' ,'error_code':'4' }";
return false;
}
Please Help.
Thanks .
Inject it in to the class or make a singleton DB class like...
Injection:
class User
{
protected $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function getDb()
{
return $this->db;
}
public function isUser($email)
{
$stmt = $this->getDb()->prepare('select count(email) as user_exists from users where email = :email');
return (bool) $stmt->execute(array(':email' => $email))->fetchColumn();
}
}
Singleton:
class Database {
protected $pdo;
protected static $instance;
protected function __construct($dsn, $user, $password)
{
$this->pdo = new PDO($dsn, $user, $password);
}
public static function getInstance()
{
if(!self::$instance)
{
// normally you would load the dsn, user, and password from a config file
$db = Config::get('db');
self::$instance = new self($db['dsn'], $db['user'], $db['password']);
}
return self::$instance;
}
public function getDb()
{
return $this->pdo;
}
}
class User
{
protected $db;
public function __construct(PDO $db = null)
{
if(null !== $db)
{
$this->db = $db;
}
}
public function getDb()
{
if(!$this->db)
{
$this->db = Database::getInstance()->getDb();
}
return $this->db;
}
public function isUser($email)
{
$stmt = $this->getDb()->prepare('select count(email) as user_exists from users where email = :email');
return (bool) $stmt->exectute(array(':email' => $email))->fetchColumn();
}
}
I hate to say this, but try just adding
global $db;
before your $db->query($sql); line. It might work, depending on exactly where the $db was created.
That said, prodigitalson's answer is a vastly improved approach, it just involves fixing your entire design, which involves more up front work :)

Extending mysqli and using multiple classes

I'm new to PHP oop stuff.
I'm trying to create class database and call other classes from it. Am I doing it the right way?
class database:
class database extends mysqli {
private $classes = array();
public function __construct() {
parent::__construct('localhost', 'root', 'password', 'database');
if (mysqli_connect_error()) {
$this->error(mysqli_connect_errno(), mysqli_connect_error());
}
}
public function __call($class, $args) {
if (!isset($this->classes[$class])) {
$class = 'db_'.$class;
$this->classes[$class] = new $class();
}
return $this->classes[$class];
}
private function error($eNo, $eMsg) {
die ('MySQL error: ('.$eNo.': '.$eMsg);
}
}
class db_users:
class db_users extends database {
public function test() {
echo 'foo';
}
}
and how I'm using it
$db = new database();
$db->users()->test();
Is it the right way or should it be done another way?
Thank you.
You can do it that way, there's nothing wrong with that (I do something similar quite often). The only thing I would suggest is using exceptions instead of die (that way you can safely handle the error)...
protected function error($eNo, $eMsg, $extra = '') {
throw new Exception('MySQL error: ['.$eNo.'] '.$eMsg.': '.$extra);
}
Plus, I'd suggest overloading the query method as well
public function query($sql, $result_mode = MYSQLI_STORE_RESULT) {
$result = parent::query($sql, $result_mode);
if ($result === false) {
$this->error($this->errno, $this->errstr, $sql);
}
return $result;
}
I'd also suggest storing a copy of the $db object inside of the child class. So:
class db_users extends database {
protected $db = null;
public function __construct(Database $db) {
$this->db = $db;
}
public function test() {
echo 'foo';
}
}
Then, in __call:
if (!isset($this->classes[$class])) {
$class = 'db_'.$class;
$this->classes[$class] = new $class($this);
}
There is nothing wrong with this factory style for creating classes. I'd place a bit of exception handling in it.
My only other concern is extending database in your sub classes.
So I'd modify as follows:
public function __call($className, $args) {
if (!isset($this->classes[$class])) {
if(include_once('db_'.$class)) {
$class = 'db_'.$class;
$this->classes[$class] = new $class($this);
} else {
throw new Exception("Db class not found");
}
}
return $this->classes[$class];
}
And the users class as:
public class db_users {
private $db;
public __constructor($db) {
$this->db = $db;
}
public function test() {
return 'Foo';
}
}

Categories