Hello there i want to learn a singleton pattern in php,
i have a class:
class Database
{
private static $instance;
private function __construct()
{
}
public static function getInstance()
{
if (!self::$instance)
{
self::$instance= new Database();
}
return self::$instance;
}
public function query($table)
{
$this->query = 'select * from $table';
}
public function result()
{
echo $this->query;
}
}
$db = Database::getInstance();
and now , is it posible to call the result() method and print the value set by the query() which is "select * from $table" using a singleton?
i want my code in something like:
$db->query('user_tb')->result();
//output
select * from user_tb;
Update:
To be able to call it like:
$db->query('user_tb')->result();
You need to put return $this; in method you want to chain, in this case your query method:
public function query($table)
{
$this->query = "select * from $table";
return $this;
}
Now you can call it like : $db->query('user_tb')->result();
Working Example
-------------------------------------------------------------------------------------------
First modify in your query() method:
$this->query = 'select * from $table';
To:
$this->query = 'select * from ' . $table;
since inside single quotes, variables are not parsed.
And then define $query at class level like this:
class Database {
private static $Instance;
private $query = '';
// your more code
}
And then you can run this to get it:
$db = Database::getInstance(); // get class instance
$db->query('user_tb'); // set $query var
$db->result(); // get $query var
Result:
select * from user_tb
Working Example
To use method chaining, make sure all functions you want to chain return $this.
Then you can do DB::getInstance()->query()->result();.=
So query at least needs to return $this.
Also, you forgo any error handling by return parameter, so generally if you use method chaining you need to use exception handling to deal with errors.
As in, you can't do
if(!$db->query) {
error_log('bleh');
}
Related
I know returning the last inserted ID when running a straight query is simple:
$query = $db->query("INSERT INTO site_stats (PageView) VALUES('1')");
if ($query) {
$id = $db->insert_id;
echo 'The ID is: '.$id;
}
However, I am running all of my queries through a class which helps me keep track of how many queries I am executing and how long it's taking. The class is simple and straightforward:
class dbLog {
public $queries = array();
public function query($sql) {
global $db;
$start = microtime(true);
$query = $db->query($sql);
$this->queries[] = microtime(true) - $start;
return $query;
}
public function getCount() {
return sizeof($this->queries);
}
public function getTime() {
return number_format(array_sum($this->queries), 5);
}
} // end dbLog class
$dbLog = new dbLog;
The problem is, when I run queries through this class, I can not figure out how to return the last inserted ID:
$query = $dbLog->query("INSERT INTO site_stats (PageView) VALUES('1')");
if ($query) {
$id = $dbLog->insert_id;
echo 'The ID is: '.$id; // Returns error
}
The error I get returned is Undefined property: dbLog::$insert_id
How can I get the ID of the last inserted row?
Since your class is just using $db from the global scope, you can use $db->insert_id as you originally did.
To do this in a proper manner you'd want to actually wrap the $db object inside your own class / object, either by extending (inheriting) from the original class and then instantiating your own, or by implementing the methods you want to expose through your own class, and giving $db to the constructor and keeping the reference internally.
You're wrapping the mysqli class in another class (you're also using global, which is not ideal)
What you need is a method to get the ID from the actual mysqli instance
public function getId() {
global $db;
return $db->insert_id;
}
If I were you I'd use dependency injection and make your mysqli instance part of the class itself
class dbLog {
/** #var \mysqli */
protected $db;
public function __construct(\mysqli $db) {
$this->db = $db;
}
public function query($sql) {
$start = microtime(true);
$query = $this->db->query($sql);
$this->queries[] = microtime(true) - $start;
return $query;
}
public function getId() {
return $this->db->insert_id;
}
}
I'm wondering how to receive the results from a function "from the class itself". An example of this is the PDO functions, where I can do the following to get i.e. the last ID:
$db->query($sql);
$id = $db->lastInsertId();
Right now I have to do the following:
$newThread = $forums->newThread('title','category');
$id = $newThread['id'];
Of course this works great, but I have to use the variable $newThread, which I don't want to. How do I save the value in order to call it later?
In case you have problems understanding how the PDO version works, it's roughly like this:
class PDO {
private $lastInsertId;
public function query($sql) {
magic_sql_api_call($sql);
/* here be dragons */
$this->lastInsertId = magic_sql_api_get_last_insert_id();
}
public function lastInsertId() {
return $this->lastInsertId;
}
}
You can create code like this
class Forums {
private $id;
...
function createTread($title, $category) {
$newThread = $forums->newThread($title, $category);
$this->id = $newThread['id'];
}
function lastId() {
return $this->id;
}
}
You can use it
$forums->createTread('title','category');
$id = $forums->lastId();
You probably will need to save $newThread in property too.
I wonder why I get errors with that code? Can Someone help?
My class is to get some information from database using nested methods,suppose I get an empty query
<?php
class db {
public function __construct(){
if(mysql_connect("localhost","root","0000")){
mysql_select_db("myblog");
}else{
echo mysql_error();
}
}
public function select($row){
$sql="SELECT".$row;
return $this;
}
public function from($table){
$sql.="FROM".$table;
return $this;
}
public function where($condition){
$sql.="WHERE".$condition;
return $this;
}
}
$ddb=new db;
$qq=$ddb->select("*")->from("news")->where("id='1'");
$query= mysql_query($qq);
while($row=mysql_fetch_object($query)){
echo $row->title;
}
?>
You have to define __toString() special method to use your object as a string:
class db {
private $sql = '';
public function __construct() {
if (mysql_connect("localhost", "root", "0000")) {
mysql_select_db("myblog");
} else {
echo mysql_error();
}
}
public function select($row) {
$this->sql = "SELECT ".$row;
return $this;
}
public function from($table) {
$this->sql .= " FROM ".$table;
return $this;
}
public function where($condition) {
$this->sql .= " WHERE ".$condition;
return $this;
}
public function __toString() {
return $this->sql;
}
}
$ddb = new db();
$qq = $ddb->select("*")->from("news")->where("id='1'");
$query = mysql_query($qq);
while ($row = mysql_fetch_object($query)) {
echo $row->title;
}
You need to be using $this in each of the methods to append to $sql
// Declare the class property
public $sql = "";
// And use $this->sql in the methods
// Also note whitespace added around SELECT, FROM, WHERE
public function select($row){
$this->sql="SELECT ".$row;
return $this;
}
public function from($table){
$this->sql.=" FROM ".$table;
return $this;
}
public function where($condition){
$this->sql.=" WHERE ".$condition;
return $this;
}
Then when you query it, use $ddb->sql, since you are not returning the SQL string.
$ddb->select("*")->from("news")->where("id='1'");
$query = mysql_query($ddb->sql);
And it goes without saying that hopefully you intend to be calling mysql_real_escape_string() on any variables you construct into your where() method. As it is, you have no particular escaping on it.
run a var_dump on $qq
That will show you the problem instantly.
To me it looks as if you are missing a couple of spaces in your query and that you aren't returning the query string $sql but instead $this in your db class
use $this->sql instead of $sql in the methods select, from, where
output the query like this: $ddb->select("*")->from("news")->where("id='1'")->sql or create a getSQL() method which just returns the $sql field and query it like $ddb->select("*")->from("news")->where("id='1'")->getSQL()
You should also consider creating a method which creates a mysql_query (not just the string) or some methods for retrieving methods, so it's easier to use.
I have created an SQL function SQLquery in a class called SQLHandling
It looks like this:
/***********************************************************
* SQLquery takes a full SQL query and runs it
* If it fails it will return an error otherwise it will return
* the SQL query as given.
************************************************************/
function SQLquery($query) {
$q = mysql_query($query);
if(!$q) {
die(mysql_error());
return false;
} else {
return $q;
}
}
Is there anyway I can use this function in other classes functions without adding
$db = new SQLHandling();
$db->SQLquery($sql);
In every function where I will use it.
I know I can run SQLHandling::SQLquery($sql); but I am trying to avoid that.
use inheritance
refer:
http://php.net/manual/en/language.oop5.inheritance.php
but still you will need to use parent::fun() or $this->fun()
or put it as a public function then use any where.
example:
<?php
function c()
{
echo "moi";
}
class b extends a
{
public function d(){
parent::c();//Hai
$this->c();//Hai
c();//moi
}
}
class a{
public function c(){
echo "Hai";
}
}
$kk = new b();
$kk -> d();
?>
You could instantiate SQLHandling on class level, like so:
private $db;
public function __construct()
{
$this->db = new SQLHandling();
}
public function x()
{
$this->db->query('X');
}
here is my sample class to why i want to nest.
include("class.db.php");
class Cart {
function getProducts() {
//this is how i do it now.
//enter code here`but i dont want to redeclare for every method in this class.
//how can i declare it in one location to be able to use the same variable in every method?
$db = new mysqlDB;
$query = $db->query("select something from a table");
return $query
}
}
Take advantage of properties.
class Cart {
private $db;
public function __construct($db) {
$this->$db = $db;
}
public function getProducts() {
$query = $this->db->query( . . .);
return $query;
}
}
You'll create the database object outside of your class (loose coupling FTW).
$db = new MysqlDb(. . .);
$cart = new Cart($db);
Isolate the common code to each method/function into another private internal method/function.
If you need to have it run once automatically for the object when it's created, this is what __construct is for.
You could have something like this
<?php
class cart
{
protected $database;
function __construct()
{
$this->database = new mysqlDB;
}
function getProducts()
{
$this->database->query("SELECT * FROM...");
}
}
?>
__construct is the function that is called when you instantiate a class.