Jump to content

Recommended Posts

Hey. I have been having this problem with a lot of objects... for a very long time. I probably just don't understand the frustrating method of error reporting for objects.

 

Here is the code that isn't working.

<?php
require_once 'constants.inc'; // Includes the constants here. They are all valid.
error_reporting(E_ALL); // Does about no good in error reporting.

$con = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASSWORD); // Looks right to me.

class PDOMySQL {

//	Various functions here including the class constructor...

function query($stmt,$vals) {
	global $con;
	$sth = $con->prepare($stmt);
	if(!$vals) {
		$sth->execute();
	} else {
		$sth->execute($vals);
	}
	return $sth;
}	
};

$database = new PDOMySQL();
?>

 

Any help you can give me at all is greatly appreciated.

Thanks,

-Seven_Rings

Link to comment
https://forums.phpfreaks.com/topic/154807-solved-problem-with-php-data-objects/
Share on other sites

Oops... I forgot to post "the problem". I cant find a way to edit the first post. I was punished on here before for double posting, but since I just read the rules, and they say nothing about it, I do not expect to be punished.

 

The error I am getting is the following: Fatal error: Call to a member function prepare() on a non-object in C:\wamp\www\index.php

 

Thanks again,

-Seven_Rings

 

EDIT: This class is full of database functions, this *is* my database script. It's not just a PDOMySQL class. :P

Seems as though $con isn't being instantiated correctly.

 

If it helps, this is what my PDO details look like although mine is in a class.:

 

<?php
            try {
                db::$__db = new PDO('mysql:host='.DB_SERVER.';'.(DB_PORT ? 'port='.DB_PORT.';' : '').'dbname='.DB_DATABASE, DB_USER, DB_PASSWORD,
                                      array(PDO::ATTR_PERSISTENT => true));
                db::$__db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

                return db::$__db;
            }
            catch (PDOException $e) {
                trigger_error('Unable to connect to the database.', E_USER_ERROR);
            }

 

It should be wrapped in a try catch as it triggers an exception if the connection fails.

 

Can you var_dump($con); after you instantiate it please?

 

@Dj Kat, so that you can extend the class with your own functions to make it even easier to access the data you need. Also to allow you to abstract yourself away from that particular implementation. My DB class uses PDO if available and mysqli if it is not and I only have to use 1 set of functions to access it. I could just as easily hook it into adodb and use it with Postgres.

 

EDIT: Sorry, meant to say that yep, connection details look fine. For some reason $con either isn't being set or isn't making it into the function.

Your error message is pretty self explanatory. Your class does not have the method "prepare". Simple as that.

 

I do not know why you are using globals with a class. If you are and think that is right you need to read more up on OOP.

 

For the global $con to work I believe you also have to define it as global at the start of the script.

 

<?php
global $con;

// rest of code below

 

The better alternative is make the PDOMySQL class have a constructor and pass the DB info to that and establish a connection in that constructor and store it as a class variable and use $this->con instead.

@premiso: I made the var global because it was inside of a function... had nothing to do with OOP. Anyways, I ended up taking your advice, which was actually the way I used to have it setup. Not sure why I changed, or that I want to remind myself. It works for now. :P

 

Anyways, there is a new problem now, and since it's of the same type, I figured I would post it here.

database.inc

<?php
require_once 'constants.inc'; // Includes the constants here. They are all valid.
error_reporting(E_ALL); // Does about no good in error reporting.

class PDOMySQL {

//	Various functions here including the class constructor...

/* This is the function that is having a problem. */
function add_active_guest($ip, $url, $time) {
	/* If we aren't tracking visitors, stop here and return. Else continue. */
	if(!TRACK_GUESTS) return;

	/* If we are tracking guests, add the active guest into the database. */
	$stmt = "REPLACE INTO ".TABLE_ACTIVE_GUESTS." VALUES (?, ?, ?)";
	$vars = array($ip,$url,$time);
	$sth = $this->query($stmt,$vars);

	/* And lastly, we will update the number of active guests since we just changed it. */
	$this->calc_num_active_guests();
}

/* Fixed this function already, here for refrence. */
function query($stmt,$vals) {
	$sth = $this->con->prepare($stmt);
	if(!$vals) {
		$sth->execute();
	} else {
		$sth->execute($vals);
	}
	return $sth;
}	
};

$database = new PDOMySQL();
?>

 

And the code that is calling it...

session.inc

			if(TRACK_GUESTS) {
			$database->add_active_guest($this->ip, $this->url, $this->time);
		}

 

database.inc is properly included and all. The error is as follows...

Fatal error: Call to a member function add_active_guest() on a non-object in C:\wamp\www\session.inc

 

OOP sometimes just doesn't feel worth the trouble. But hopefully someone can shed some light on what I am missing here...

 

Thanks!

-Seven_Rings

Where is the code where you actually call add_active_guest.

 

$database has not been defined as a class. Are you calling it in a function? If so I would have to referrer you to variables scope.

 

As far as that being the way it "was" (the global comment), I am not a mind reader. I just see what you post.

I posted the code that was calling add_active_guest... I'll post it again with the rest of the function (which is also inside of a different class).

 

<?php
class Session {
     // Class constructor and other functions...

function start_session() {
	global $database;
	session_start();

	$this->logged_in = $this->check_login();

	$this->url = $_SESSION['url'] = $_SERVER['PHP_SELF'];
	$this->ip = $_SERVER['REMOTE_ADDR'];

	if(!$this->logged_in) {
		$this->username = $_SESSION['username'] = GUEST_NAME;
		$this->userlevel = GUEST_LEVEL;
		if(TRACK_GUESTS) {
			$database->add_active_guest($this->ip, $this->url, $this->time);
		}
	} else {
		if(TRACK_USERS) {
			$database->add_active_user($this->username, $this->url, $this->time);
		}
	}

	/* Remove inactive visitors from database */
	$database->remove_inactive_users();
	$database->remove_inactive_guests();
   }
};
$session = new Session();
?>

database.inc is included in the same source as the code I posted, so $database should be an instance of the PDOMySQL class. And I am globalizing $database because I am calling it from within a function. I have been coding for quite a while now, and I am pretty sure that is the correct thing to do.

 

Hopefully between this and the last post, the answer will be obvious.

Thanks for your time,

-Seven_Rings

I think we still get to the point of the variable scope.

 

global $database;
$database = new PDOMySQL();
?>

 

If you add that it should work for the session. As far as this being a good way to do it, it is not. I would look more into OOP Programming in PHP.

Are you including the file that starts up $database before you call $session->start_session()?

 

If so something is either un-setting $database or $database isn't getting set correctly.

 

@premiso, pretty sure there's no need to do that (unless you're instantiating the object within a function).

Well, instantiating the class inside the function DID work. But I am including database.inc before I am trying to call it. I am including database.inc and session.inc on the same page. And I am not resetting $database anywhere. Database is included first.

 

If instantiating the class inside the function isn't the way to do it, than what is? I have done a bit of reading on OOP, but if you know the answer, I would certainly like to hear it.

 

Thanks,

You guys are great.

-Seven_Rings

I'm pretty sure that in your code something is unsetting database. Try:

 

var_dump($database);

 

just after you set it

 

and also just before you call $session->session_start()

 

I'll bet you get two different values. Your code looks fine, from what you've posted it should work.

 

As for how to do it "properly" there are a few ways. Your PDOMySQL class could be a base class that all other classes inherit from (if this is the case the connection link will need to be static). Or you could make your DB class entirely static. Or you could instantiate it each time inside whichever class you need it in but this is arguably not the most efficient way of doing it

 

Singleton is a good way to go with a DB class. This would ensure that only one copy of the class is ever instantiated. Then where you use it, you just "re"-instaitate the object. Although it does not actually re-instantiate it. Instead it gives you the already instantiated object.

 

This way you do not have to use global for it. An example:

 

<?php
class testSingleton {
private static $instance;

        public function __construct() {
                echo "Test Construct<br />";
        }

        public function test() {
                 echo "This is the test function<br />";
        }

// delivers the current instance of this class "singleton"
public static function getSingleton() {
	if (!isset(self::$instance)) {
		$c = __CLASS__;
		self::$instance = new $c();
	}

	return self::$instance;
}
}

class testSingletonTwo {
         private $testOne;
         public function __construct() {
                 $testOne = testSingleton::getSingleton();
                 $testOne->test();
         }
}

function testThree() {
          $testOne = testSingleton::getSingleton();
          $testOne->test();
}

testThree();

$singletonTwo = new testSingletonTwo();

?>

 

There is a rough break down. Be cautious when using them and only use them for classes (such as a database class) that actually need it.

You where right. The var_dump after: $database = new PDOMySQL(); was great... but before I called start_session it was NULL. I have no idea how this could be happening.

 

I like the extending ideas, but would it be better for me to use a singleton, or to make Session extend PDOMySQL?

 

Asking expert advice on which is better in my case, since you guys probably have a decent idea of what my script is. *Mostly a login system right now*

 

Thanks again,

-Seven_Rings

You where right. The var_dump after: $database = new PDOMySQL(); was great... but before I called start_session it was NULL. I have no idea how this could be happening.

 

I like the extending ideas, but would it be better for me to use a singleton, or to make Session extend PDOMySQL?

 

Asking expert advice on which is better in my case, since you guys probably have a decent idea of what my script is. *Mostly a login system right now*

 

Thanks again,

-Seven_Rings

 

It would be better for a singleton in this case vs extending. You really should only extend when you have a base class and the extended class does just that. Such as for an example you have an Address class. Then for the collection you have an Addresses class, which extends the address. As every address has the base essentials, street, city, zip etc. But then the addresses can add information, such as company name, contact name etc incase a person has more than one address (billing/shipping) but you do not want to have to re-create all the fields for the different class.

 

Hopefully that is clear. I got interrupted halfway through and distracted.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.