Somewhat new to OOP - class interaction...?
Moderator: General Moderators
Somewhat new to OOP - class interaction...?
I am sort of a OOP beginner...
My question is... how do people generally make their classes interact. Let's say I have a database functionality class that does things like accepts queries and returns results, and I have another class that needs information from a database... is it proper to call a class from within a class, or is it generally a better idea to have a seperate file that does all of the interaction?
this question barely makes sense
My question is... how do people generally make their classes interact. Let's say I have a database functionality class that does things like accepts queries and returns results, and I have another class that needs information from a database... is it proper to call a class from within a class, or is it generally a better idea to have a seperate file that does all of the interaction?
this question barely makes sense
- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
Look up the three Design Patterns mentioned in the topic title - viewtopic.php?t=48945
I'm assuming you are referring to injecting a class dependency, where one class needs others in order to do something useful. You can either pass an instance of the required objects into your object's constructor, or grab them from the objects constructor using some sort of Singleton (either of the objects needed, or something else which knows where to get them), etc. An example with the linked to ServiceLocator might use for a simple News class:
Am on the right track in what you were asking?
I usually prefer using something similar to above (though usually a Registry) since you reduce the classes dependency to one object (whih can fetch instances of what you need) rather than grabbing each object individually (which makes for either a hard to change constructor, or a long constructor parameter list).
You can also do (as a parameter):
I'm assuming you are referring to injecting a class dependency, where one class needs others in order to do something useful. You can either pass an instance of the required objects into your object's constructor, or grab them from the objects constructor using some sort of Singleton (either of the objects needed, or something else which knows where to get them), etc. An example with the linked to ServiceLocator might use for a simple News class:
Code: Select all
<?php
class News {
private $db = false; // ADOdb connection object (database abstraction)
public function __construct()
{
// include database connection (this class is dependent on ServiceLocator to get other object instances)
$sl = ServiceLocator::getInstance();
$this->db = $sl->getService('DatabaseAbstraction');
}
public function getNewsById($newsId) {
$result = $this->db->Execute('SELECT * FROM table_news WHERE news_id = ?', array($newsId));
if(!$result)
{
trigger_error($this->db->ErrorMsg(), E_USER_ERROR);
}
return $result->fields;
}
// ...
}
?>I usually prefer using something similar to above (though usually a Registry) since you reduce the classes dependency to one object (whih can fetch instances of what you need) rather than grabbing each object individually (which makes for either a hard to change constructor, or a long constructor parameter list).
You can also do (as a parameter):
Code: Select all
<?php
class News {
private $db = false;
public function __construct($db)
{
$this->db = $db
}
// ...
}
?>
Last edited by Maugrim_The_Reaper on Thu May 25, 2006 11:15 am, edited 1 time in total.
If I'm understanding your quesion properly, you mean something along the lines of Class 1 instantiating Class 2 and using member objects/functions of it? I find no problem with that. This sort of thing falls under the class inheritance/extension principle of programming. I don't think you'll run into the need for extensions if your using a database class alongside a class that needs to interact with a database. It's definitely a sound way to have the database class have built in error-protection/checking for modularity for later use.
And if it is improper, well, uh oh, because that's the way I do a lot of my projects
And if it is improper, well, uh oh, because that's the way I do a lot of my projects
you guys actually know exactly what I was asking... man.. you're good!
Do you see what I am trying to accomplish? I just don't want to have a class that does nothing but return queries... seems a waste of space
Code: Select all
class orderUpload{
var $products = array();
var $order_id;
function orderUpload($order_id, $dbh){
// Class constructor
// Takes an order id as it's first argument and a database handle as its second.
// Constructer gets products in order and applies them to the property $this->products
$this->order_id = $order_id;
$this->dbh = $dbh; // This is the database instance
// Get id and quantities of products in order and assign them to $products array
$sql = "SELECT product_id, code, quantity FROM s01_OrderItems WHERE order_id = " . $this->order_id;
if($r = $this->dbh->select($sql)){ // This line is using the instance
while($row = $this->dbh->get_row($r, "MYSQL_ASSOC")){ // This line is using the instance
$this->products[] = $row;
}
}
else{
// failed to run sql query
echo "error";
}
}
function checkPhotoNeeded($product_id){
// This method takes a product id as an argument and returns true if it finds that this product needs a photo.
// This method makes use of a table in the database called s01_ProdValues
$sql = "SELECT value FROM s01_CFM_ProdValues WHERE product_id = " .$product_id;
strtolower($this->dbh->select_one($sql)) == "yes" ? return true : return false; // This line is using the dbh instance
}
}- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
That gets very hard to maintain as the source code grows. What if you change a class name? Go back and edit the umpteen classes using the older class name to create an instance? Using some sort of class to package instances is easier to manage - I can just change the DatabaseAbstraction reference to point to another Abstraction class entirely from a single point - where ever I called the ServiceLocator's registerService('DatabaseAbstraction', $adodb)... Maybe not a great example (any app likely has only the one database objects in use)...but the principle is the same.If I'm understanding your quesion properly, you mean something along the lines of Class 1 instantiating Class 2 and using member objects/functions of it? I find no problem with that.
In general I don't think classes should be responsible for instantiating other classes they need unless it's essential or obviously makes good sense.
- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
Code: Select all
class orderUpload{
var $products = array();
var $order_id;
function orderUpload($order_id, $dbh){Code: Select all
function orderUpload($order_id, &$dbh){Well, the way I do my projects keeps actual code maintenance at a very high priority. Before I even start programming, I lay out everything that I know, and everything that is required for the project, and I write down all the classes, objects, functions, pre/post conditions, etc for just about everything (pseudo code sometimes if I think of it). This way I have set class names before I've even written a single class.Maugrim_The_Reaper wrote:That gets very hard to maintain as the source code grows. What if you change a class name? Go back and edit the umpteen classes using the older class name to create an instance? Using some sort of class to package instances is easier to manage - I can just change the DatabaseAbstraction reference to point to another Abstraction class entirely from a single point - where ever I called the ServiceLocator's registerService('DatabaseAbstraction', $adodb)... Maybe not a great example (any app likely has only the one database objects in use)...but the principle is the same.
In general I don't think classes should be responsible for instantiating other classes they need unless it's essential or obviously makes good sense.
And yes, instantiation of the actual object is best to be handled outside of classes. The wording was chosen pretty poorly on my part, when I was really just thinking of member objects having an instance of another class (and on a few projects of mine, the container class creates a new instance of an object, when the old object needs to be recreated for whatever reason), ie:
Code: Select all
class Liquid {
function __construct($a) {
$this->type = $a;
}
}
class Cup {
function __contstruct($liquid) {
$this->contents = $liquid;
}
}
$water = new Liquid("ice");
$mycup = new Cup($water);Thank you... very helpfulMaugrim_The_Reaper wrote:Looks fine in practice.Code: Select all
class orderUpload{ var $products = array(); var $order_id; function orderUpload($order_id, $dbh){Unless it gets more complex and you start pushing lots of objects in as constructor parameters, or end up passing the $dbh object across several layers, then you can probably do without a Registry. I would make one small change assuming you are coding for PHP4 (which seems likely). Use:
This ensures the $dbh objects is passed by reference in PHP4, otherwise the object you receive will be a copy. Many copies doing the same things equals lots of wasted memory. In PHP5, all objects are automatically passed by reference - PHP4 needs those ampersands attached to object parameters.Code: Select all
function orderUpload($order_id, &$dbh){
Can somebody elaborate on this methodology a little?
Code: Select all
# Using non-instantiation:
class a {
Function foo() {
echo 'hello';
}
}
class b{
var $a;
function b() {
a::foo(); // What exactly does :: do?
}
}It calls the member function foo() of class a. It works because the function foo() does not require an active instance of the object (class a in this example) for it to return a value or process something. It would not work for the following because foo() is trying to call an object of class a, and in this case there is no active instance of a to get the value for.The Ninja Space Goat wrote:Can somebody elaborate on this methodology a little?
Code: Select all
# Using non-instantiation: class a { Function foo() { echo 'hello'; } } class b{ var $a; function b() { a::foo(); // What exactly does :: do? } }
Code: Select all
class a {
Function foo() {
echo $this->something;
}
}
class b{
var $a;
function b() {
a::foo();
}
}- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Code: Select all
class orderUpload{
var dbh;
var $products = array();
var $order_id;
function orderUpload($dbh){
$this->dbh = $dbh; // This is the database instance
}
function orderUpload($order_id){
// Class constructor
// Takes an order id as it's first argument and a database handle as its second.
// Constructer gets products in order and applies them to the property $this->products
$this->order_id = $order_id;
....
}Actually the goal as to have a lot of small, clean, focused classes. A class should be useful once initialized (hence passing he $db to the constructor) and be responsible for doing one thing well. If more needs to be done then extend or composite.he Ninja Space Goat wrote:Do you see what I am trying to accomplish? I just don't want to have a class that does nothing but return queries... seems a waste of space
(#10850)
Yep, sort of. In the second one, when you try to reference $this, it will return an error because $this is trying to reference an object that was never created.The Ninja Space Goat wrote:hmm... I think I get it...
it works in the first one because there is no need for the class to be instantiated, but not the second because the class would have to be called previously for $this->something to be set?
Close?
If you did a "new a()", and did a->foo() using the second method, it would work but print nothing because $this->something is a null value. Whereas if you did not create a new a object, it would throw an error because there is no object to try to even call $this->something for.
I'm so bad at explanations
So be careful, because $this doesn't exist yet!
- RobertGonzalez
- Site Administrator
- Posts: 14293
- Joined: Tue Sep 09, 2003 6:04 pm
- Location: Fremont, CA, USA
OK, so I have a question about this. I was told on these forums (somewhere) that globalizing an object/var for use in a class was not the right thing to do. What I have done is something along this lines of...
So should I be using a reference to the $db object instead of using a global? I have wondered about this for a bit and I think this is a good place to pose the question (seeing as Ninja's is somewhat similar).
Code: Select all
<?php
class MyClass
{
function MyClass()
{
global $db; // This is my DBAL object
/* Do something here using the $db object */
}
}
?>