Jump to content

Using objects inside objects ...


nloding

Recommended Posts

I have several classes in individual include files.  As an example, we'll use my database class and my user class.  They do what their names imply.

 

In short, what is the most proper way to include the database object into the user object?  I've seen MANY ways of doing it, but I've also read it's not a good thing to use global objects like that.

 

Should I do this?

 

class Database {
  function Database {
    // connect to database
  }
}

$db = new Database;

class User {
  global $db;
  function User {
    // set $username or whatever
  }
}

 

... or ...

 

$db = new Database
$user = new User($db);

 

Or what?  I'm confused ...

 

EDIT: I should also add that the database class is used in multiple classes in my page (an archive class, a forum class, a security class, and the user class).

Link to comment
Share on other sites

The question all depends on how big your project is and how you want to implement it.

 

The 'norm' is to include DAO's (Data Access Objects) inside of the class. Don't use globals.

 

Depending on the size of the project, on larger projects I would probably implement an Abstract Factory (http://en.wikipedia.org/wiki/Abstract_factory_pattern) DAO Layer. Seems to be my favorite pattern ;)

 

If you have any specific questions, let me know :)

Link to comment
Share on other sites

That abstract factory pattern looks intriguing, I'll have to look into it.  For the scope of this current project, something like that is VERY UNnecessary.  However, what this project is building up to, something like that could be enormously helpful.  Thank you for the link -- since OOP is new, a lot of design patterns are new too.

 

For right now, this is basically what I'm doing, and while not perfect, it seems to be working for the scale of the site.  If there is something wrong with this, please point it out (I fail to see it):

 

<?php

class Database {
  function Database() {
    // build the connection, whatever
  }
}

class User {
  private $db;
  function User($dbObj) {
    $this->db = $dbObj;
    // do something
  }
}

$database = new Database();
$user = new User($database);
// same for other objects
$forum = new Forum($database, $user);

?>

Link to comment
Share on other sites

My only problem with this approach is you always have to pass this Database object around to every constructor.

 

What if, theoretically, at some point in the future, you'll need 2 databases. Some objects use DB1, Some objects use DB2 (Think statistics generation, whatever) You'd have to modify your script to meet the objects new requirements, which breaks the rule of encapsulation.

 

If you take what I said in to account, you'd have to go with an approach which looks like this:

 

<?php

class Database {
  function Database() {
    // build the connection, whatever
  }
}

class User {
  private $db;
  function User() {
    //initialize object specific properties
    $this->db = new Database();
    // do something
  }
}

$user = new User($userName);
// same for other objects
$forum = new Forum($database, $user);

?>

 

This leads to another problem. What if you want to have n types of users (Anonymous, Registered, Administrator) If it were me, I would rewrite what is above similar to the following:

 

<?php

interface DatabaseConnection {
   //set up a connection
   function connect($conString, $userName, $password);
   //executes a query..
   function query($q);
}

interface User {
    function permission($obj) // bool, returns if the user has permission to edit property.
    //insert some other user level functions
}

class Database implements DatabaseConnection {
  private $connection;
  function Database() {
     $this->connection = $this->connect("localhost", "user", "pass");
  }
   
  function connect($...,) {
  }

  .
  .
  .
  //etc
}

class Administrator implements User {
  private $db;
  function User() {
    //initialize object specific properties
    $this->db = new Database();
    // do something
  }

  function permission($obj) {
     return true; //administrators can view everything
  }

}

$user = new User($userName);
// same for other objects
$forum = new Forum($database, $user);

?>

 

A special thing to note is this is only a suggestion and no matter which way you decide to design, the end result is all that matters unless you're working professionally.

 

Good luck !

Link to comment
Share on other sites

Wow, talk about making my head spin in circles for a minute.

 

I think I see it ... I think ... took me several tries with OOP (how to encapsulate everything so it made sense and wasn't just procedural under another name) ...

 

I've printed off some articles about design patterns and factory/abstract factory patterns and I'll read through those tonight.

 

I think I see it ... it's creating a new database object for each instance of the Administrator class.  But that almost reads backwards to me ... it seems like User should implement Administrator, rather than the reverse as you have above.  If the interface (which granted, I don't really know what that keyword implies in PHP, just what it means in the dictionary) User has the method 'permissions', why then create a class Admin implementing User when Admin has ANOTHER method called 'permissions' ... ?????

 

Yeah, head circling, time to read some more articles ...

 

EDIT: Wait, wait, in the interface, you aren't *defining* those functions, are you?  You're just stating they exist for all instances of User ... then the class which implements the interface then defines what that method does for the instances the User is an Administrator ...

 

So what differentiates between the different implementations of User ... where is the Administrator object called?

 

If that's what it is, I see a lot of power and flexibility, and finally a good reason to use OOP.  How far off am I?

Link to comment
Share on other sites

That abstract factory pattern looks intriguing, I'll have to look into it.  For the scope of this current project, something like that is VERY UNnecessary.  However, what this project is building up to, something like that could be enormously helpful.  Thank you for the link -- since OOP is new, a lot of design patterns are new too.

 

For right now, this is basically what I'm doing, and while not perfect, it seems to be working for the scale of the site.  If there is something wrong with this, please point it out (I fail to see it):

 

<?php

class Database {
  function Database() {
    // build the connection, whatever
  }
}

class User {
  private $db;
  function User($dbObj) {
    $this->db = $dbObj;
    // do something
  }
}

$database = new Database();
$user = new User($database);
// same for other objects
$forum = new Forum($database, $user);

?>

 

Object-oriented programming is certainly not new, it's been around since 1972. approx.

Link to comment
Share on other sites

EDIT: Wait, wait, in the interface, you aren't *defining* those functions, are you?  You're just stating they exist for all instances of User ... then the class which implements the interface then defines what that method does for the instances the User is an Administrator ...

 

So what differentiates between the different implementations of User ... where is the Administrator object called?

 

If that's what it is, I see a lot of power and flexibility, and finally a good reason to use OOP.  How far off am I?

 

! Yes. Tons of power and flexibility. A really, really good book to read which will make a lot of this click, is Holub on Patterns. It helped me tremendously. It's a 'Java' reference book, but design patterns and OOP are really language agnostic.

 

Extending on the user class above, think of the User class as a template. It just defines how objects which implement it must looks like, not the functionality they posses.

 

To take it one step further, consider this terrible implementation of OOP:

 

<?php

class User {
   private $name;
   private $type; //$type = admin, regular, anonymous
   function User($name) {
        $this->init($name);
   }

   function init($name) {
      $this->db = new Database();
      $udata = $this->db->q("select * from user where name = " . $this->name);
      $this->type = $udata['type']
   }

   function permission($obj) { //check if the user has permission to view $obj
       if ($this->type == 'admin') {
           //blaa bla bla
       } elseif ($this->type == 'registered') {
            // bla bla bla
       } else {
            // bla bla bla
       }
   }
}

 

Compare this method to the templated version, and you'll truly see the power of interface programming :)

 

You're on the right track!

Let me know if you have any more questions

Link to comment
Share on other sites

So I've found a few articles on factory design patterns (I started with the Singleton pattern for ease) and I'm still confused about *how* the factory chooses which class it's implementing.  Take, for instance, the article here: www.patternsforphp.com/wiki/Abstract_Factory .  They use a third class, Settings, to pull an array from an INI file (you have to find their Singleton article to know that).  Then uses a switch statement.  Using an INI file, having to parse it, then still using a switch statement that is no different from the one they had earlier in the article -- I don't get it, unless just a really dumbed down version.  The only thing they did was put it in a class instead of a function so it looks prettier in the markup -- which isn't truly utilizing something like the Abstract Factory (I don't think).

 

I've found a few more articles on devshed that seem pretty good as they use real examples (form validation, for instance) that I haven't read yet.

 

But take for instance your example with User and Administrator above -- when you go '$user = new User($username)', what logic chooses 'Administrator' over 'Guest'?

Link to comment
Share on other sites

Good question.

 

In my example, it doesn't. If it did, that would be an Abstract Factory pattern, though. I can't think of a solid idea of an Abstract Factory working with a user, though, since normally you would build a user instead of having one created for you.

 

I'll think about this, and maybe someone else may feel the need to chime in :)

 

But take for instance your example with User and Administrator above -- when you go '$user = new User($username)', what logic chooses 'Administrator' over 'Guest'?

 

This would be done on whatever object(s) control the display of your content. Take for instance:

 

<?php
class Display {
      function display(User $user, $obj) {
           if ($user->permission($obj)) {
                 //display form/page/header/extra content/whatever you want
           }
      }
}
?>

// example client
$f = new Form($someData);
$u = new Administrator("keeb"); // Administrator implements User
$d = new Display();
$d->display($u, $f);

 

Notice the above function doesn't care about what type of user is being passed to it, and doesn't even check. It just checks if the user has permission to display the object, and is done with it.

 

I hope this clears some things up ;)

 

 

 

Link to comment
Share on other sites

The difference between an interface and an abstract class is that abstract classes can have code inherited by child classes, which interfaces are just templates defining methods required by implementers

 

<?php
abstract class Butthole {
     private $diameter = 10; //i can also defined inherited properties here..
     abstract function anal();
     function insert($obj) { // hehehe
         //defining this function here because objects are 
     }
}


// or, maybe, i want to have multiple animals which have buttholes, so I define an interface, and leave it up to the child for implementation details.

interface Butthole {
     function anal();
     function insert($obj);
}

// oh and, maybe I want my Camel class to also have a mouth.

interface Mouth {
      function eat($obj);
} 

class Camel implements Butthole, Mouth {
       //anal, insert, and eat must be defined
}

?>

 

I hope you liked my (crude) example! :)

 

 

Link to comment
Share on other sites

The difference between an interface and an abstract class is that abstract classes can have code inherited by child classes, which interfaces are just templates defining methods required by implementers

 

<?php
abstract class Butthole {
     private $diameter = 10; //i can also defined inherited properties here..
     abstract function anal();
     function insert($obj) { // hehehe
         //defining this function here because objects are 
     }
}
?>

// or, maybe, i want to have multiple animals which have buttholes, so I define an interface, and leave it up to the child for implementation details.

interface Butthole {
     function anal();
     function insert($obj);
}

// oh and, maybe I want my Camel class to also have a mouth.

interface Mouth {
      function eat($obj);
} 

class Camel implements Butthole, Mouth {
       //anal, insert, and eat must be defined
}

?>

 

I hope you liked my (crude) example! :)

 

 

 

I get this, quite clearly.. but why use the interface because if you're going to use them functions, you're going to use them functions.. will you get an error if you don't use all the functions implemented from the interface or would you get an error if you use more functions that were defined by the interface?  Why do you need to name them before hand?

Link to comment
Share on other sites

I get interfaces -- it's more for troubleshooting ... a 'roadmap' as I called it ... I kinda like it though it is more typing.  So alright, let's talk real-world ... I'm sick of some of the idiot examples I'm seeing of the factory and abstract factory patterns.  Back to my original post, how would that work with the page I was talking about?

 

Now that I look at this code, it's redundant and ridiculous, and doesn't fit what I wanted, but it's a start and I'm trying.  For the terms of the original post, how ridiculous is this?  [Note: ignore scope of variables inside the classes, I just didn't spend time defining them as private, protected, whatever]

 

<?php
/**
* Attempt at understanding the Factory and Abstract Design Patterns
*/

interface DatabaseManager {
// Connect to the database
function connect($host, $user, $pass, $dbname);

// Query the database
function query($q);
}

class DBMgr implements DatabaseManager {
function DBMgr() {
	$this->dbase = $this->connect('localhost', 'user', 'pass', 'dbname');
}

function connect($host, $user, $pass, $dbname) {
	$this->temp = mysql_connect($host, $user, $pass);
	mysql_select_db($dbname, $this->temp);
	return $this->temp;
}

function query($query) {
	$this->result = mysql_query($query);
	$this->numQueries++;
	return $this->result;
}
}

// ...

interface Forum {
// initialize the forum
function initialize($forum);

// pull subforums
function showSubforums();

// ...
}

class MyForum implements Forum {
function __construct() {}

function initialize($forum) {
	$this->db = Factory::instantiate('database');
	$this->title = $this->db->query("SELECT title FROM forums WHERE forum_name='$forum'");
}

function showSubForums() {
	$this->db->query("SELECT subforums FROM forums WHERE forum_name='$this->title'");
}
}

// ...

abstract class databaseFactory {
private function __construct() {}

private static function get() {
	static $instance;

	if(!isset($instance)) {
		$class = __CLASS__;
		$instance = new DBMgr();
	}

	return $instance;
}
}

abstract class forumFactory {
private function __construct() {}

private static function get() {
	return new MyForum();
}
}

abstract class Factory {
private function __construct() {}

private static function instantiate($type) {
	if(!class_exists($type)) {
		throw new Exception('Not a class, dummy!');
	}

	$class = $type . 'Factory';
	return $class::get();
}
}

// .....

$forum = Factory::instantiate('forum');
$forum->initialize('phpFreaks');

?>

Link to comment
Share on other sites

That factory produces only a single instance of itself, ever.  For the small site I have right now, I thought that would be incredibly handy for a database connection, so as to not stress the connections.  The $class variable refers to itself, so it can then be instantiated, once, in the line beneath.  That much I get :)

 

I guess where I'm losing myself in all of this is where the division of the classes happens.  So I've got a forum class, then probably a subforum class, then a thread class, then a post class.  Then there's a page class, and form class that extends it, or something.

 

It seems ... a little redundant.

 

keeB (or anyone else) -- please review the code I posted and make sure it all fits together.  I get some parsing errors in Zend Studio on lines like $class::get();.  It seems to work when I throw it at a browser, but I dunno how well it would truly work when implemented in a full site.

Link to comment
Share on other sites

That factory produces only a single instance of itself, ever.  For the small site I have right now, I thought that would be incredibly handy for a database connection, so as to not stress the connections.

 

Your forgetting that PHP is not a persistent state, like it would be in, say, Java.

 

I guess where I'm losing myself in all of this is where the division of the classes happens.

 

Please review this link: http://c2.com/doc/oopsla89/paper.html .

 

Now we're getting in to real design discussion, and for something like that to happen, you need to have solved the big picture before you can start actually writing code. That is why I always say, you need to consider the size of your project to really gauge how 'right' you want to do things.

 

The CRC method is great for figuring out exactly what objects you need, and forces you to think about how each component will talk/interact with each other.

Link to comment
Share on other sites

In OOP, this is a standard 3-tier architecture like scenario.. and i believe thats the best way.

 

1. Have a data layer dataL.class.php

2. Have all your data access implementation within this class. including sql query's, opening closing  connections, executing and returning values.

3. Have all your sql in this class as private constants like

$user_ins = "insert into users (name, email) values ('@name@','@email@');"

4. Create methods in the data layer class like

public function user_add($name, $email)

{

    $query = $this->user_ins;

    $query = str_replace("@name@",$name,$query);

...

 

call execute functions.. and return the result required...or just return true/false.

}

 

I use this.

http://www.floresense.com/resc_center/?c=3&art=1393

 

 

regards,

Harish

www.harishpalaniappan.com

www.floresense.com

Link to comment
Share on other sites

I like some things within the class you linked to, but that query method seems ridiculous.  Even if you're constantly changing db systems.  Either way, you have to go in and change the query string; but if you're adding values, you have to go touch the function anyhow to add the arguments and add another str_replace.

 

That being said, I like the way your class processes the queries and am going to borrow the concept and tweak my database wrapper.

Link to comment
Share on other sites

The 'norm' is to include DAO's (Data Access Objects) inside of the class.

 

Indeed DAO's seem to have gained much popularity, although the PHP implementation is usually different in that it skips over the creation of Transfer Objects.

 

I personally much prefer Data Mapper because the client is less dependent on a Mapper than on a DAO. It allows the Domain Model to be ignorant of the rest of the Data (Integration) Layer. It also plays more nice with Identity Map and Unit of Work, as DAO's are supposed to be stateless* and do not actually create any objects as Data Mapper does.

 

*Quote Alur et al. 463

The DAO is implemented as a stateless object. ... This makes the DAOs lightweight objects and avoid potential threading and concurrency issues.

 

Link to comment
Share on other sites

I should point out that implementing DAO's is easier though. It also has the potential benefit of lazy initialization, although Data Mapper can  use it's own lazy loading strategies such as Virtual Proxy or Ghost (which is also a little more work to implement than lazy initialization).

 

Lazy initialization with a DAO:

 

<?php
class UserGroup {

private $users;

public function getAllUsers(){
	if($this->users === null){
		$dto = $this->dao->getAllUsers();
		foreach($dto as $to){
			$this->users[] = User::factory($to);
		}
	}
	return $this->users;
}
}
?>

 

Because with Data Mapper the Domain Objects must stay ignorant of the Mapper, you have to go through a little trouble:

<?php
class UserGroupMapper {

public function find($id){
	//Get data from store//
	return new VirtualUserGroup($data, DataController::getMapper('User'));
}
}
class UserMapper {

public function findForGroup($groupId){
	//Get data from store//
	return $arrayWithUsers;
}
}
class VirtualUserGroup extends UserGroup {

public function __construct($data, UserMapper $userMapper){
	parent::__construct($data);
	$this->userMapper = $userMapper;
}
public function getAllUsers(){
	if($this->products === null){
		$this->products = $this->userMapper->findForGroup($this->id);
	}
}
}
?>

 

This is not the best possible way to do this though...

Link to comment
Share on other sites

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.