Accessing other Same-Level Objects

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Accessing other Same-Level Objects

Post by Ambush Commander »

The title's a bit obtuse, so I'll try to explain.

Let's consider a database system where we have an author: this author is represented by the class TWP_Data_User_Author. Inside, we have an array of TWP_Data_Story objects (which each have TWP_Data_Chapter objects in them). The Author object contains information about the author, such as Real Name, email address, etc.

Let us consider we have another type of class: TWP_Data_User_Project. This is a project that people can participate in: it's sorta like an author, but has many differences.

Our TWP_Data_User_Author "bob" has participated in TWP_Data_User_Project "wikipedia". His author page will display some relevant information about TWP_Data_User_Project.

The question, now, is where we put the TWP_Data_User_Project.

Currently, the main object is TWP_Data_User_Author "bob", and that's the basis of the page display. In order to grab information about TWP_Data_User_Project while using methods inside TWP_Data_User_Author, we could store the project in a variable in the object, like: $this->project_object

However, there are also project pages, which display information about the authors who have participated in this project. If we were to follow similar logic, there would be a $this->author_object variable. As you can see, this could lead to infinite recursion.

When you use an object, it may need to access the information of another object: but when this object is not clearly within it's hierarchy, trying to put it as a lower-level object will cause organization problems. This means:

Code: Select all

Rule: Author contains Project
Rule: Project contains Author
Author contains {Project contains {Author contains ...}}
It doesn't make sense, and it the fix is ugly (probably involves passing a variable stating how many times you should recurse through the object)

But does this mean we create a global object that contains all the Author and Project objects? And if that's the case, how would an Author object access information from a Project by using one of it's own methods?

Obviously, $this->project won't work. Is it possible using only Author's methods? Does this mean interobject methods have to be stored independent of the Author and Project objects?

I'm a bit confused, but this seems like a kind of question that has been addressed in past programs. What is the correct design for this sort of situation?
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

It might help to stop thinking about the data. Instead think about the domain layer: try and identify discrete roles and write lean classes which do just one thing - "do-ers" rather than nouns.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Well, what I want to do is have the object represent the data, and I want it to do all the populating too, a sort-of integrated mapper class. Then, the program just accesses the values it needs from the object.

Maybe I should seperate the Mapper to another class?
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

OK so this is more an object-relational mapping problem? I can't recommend Martin Fowler's Patterns of Enterprise Application architecture too highly (a taster here). It's essential reading for all programmers. He's very lucid on general design issues and there's a lot in the book about O/R. I've never had to create anything too complicated so I'm not sure if I can help much with the more complex database stuff.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Well, it's not exactly the mapping for Databases, because I was planning on building the interface before the mapping. I currently have this really inefficient system for storing data, and I'm going to port it to MySQL, but first, I wanted to redesign the way I accessed the data.

So, I started coding an Author class that you could initialize by an id and then would make a query to the original "database" and fill up the entries. This was all fine and dandy until I realized that I also needed to access other "objects" (as I mentioned earlier). I, personally, don't think there's anything complicated about it. :oops:

Wait... this may be a problem with external data caching. If you have a object that needs to be aware of ten other objects, the best solution probably isn't to initialize those objects every time you need to handle this one object, instead, store cached information in that single object of what you need. Is that correct?
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

I'm not sure I really understand the problem well enough but as you say maybe you could try to design the classes so that, in each request, only the objects you really need are invoked.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Well, say you have a project with 50 members. Obviously, you don't want to invoke all 50 member objects.

Ugh... how to explain?
fastfingertips
Forum Contributor
Posts: 242
Joined: Sun Dec 28, 2003 1:40 am
Contact:

Post by fastfingertips »

As you may notice you will make an UML or just try to make a database design you will notice that there is an n-n relation, so you will need additional information in order to get lets say history of all users from a project;

instead to set

Code: Select all

$this->_intProjectId = 1;
try to add additional details

Code: Select all

$this->_intProjectId = 1;
$this->_intProjectMembet = 2;
and to your method send this two properties instead of one :)
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

I'm not sure I exactly understand what you're saying, could you explain more clearly?

I've been reading up on SQL recently, however, and I'm thinking the best way to resolve this issue is just to not to pass things around hierarchally. Allowing information that would have been queried for unrelated functions to be used again is just information caching, and that can be handled with its own framework.
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

Meaby you want to have a look at http://www.ezpdo.net...
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

PHP4, unfortuantely. I'll though I will take a look.
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

Perhaps you want to look at doing lazy initialization.

For instance the author doesn't fetch the data until the "get" method. Then creating a container with lots of Authors isn't a huge upfront cost. You'll still have to load all the data eventually, but it might save some.

Then if preformence dictates it later, you could potentally implement a bulk loader in the collection class that could use a more efficient query, etc.

I personally would like to keep my objects as lightweight as possible, so I don't mind having large collections/iterations on them. Thus a lazy initialization paradigm tends to help.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

That sounds about right. It means that I'd have to make functions for accessing all variables, but it's not that unreasonable. Plus, even if you load the data, the Project doesn't need all the information about the authors, just some of it, so lazy initialization means that some of the information is retrieved, not all of it, and you still get to use the same object class.
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

Yes, but also when dealing with the DB, you don't want to do too many small queries. So, on the first request for data from an Author, I'ld probably pull in most of the referenced data.

Ie the real name is requested, I'ld pull in Email, etc as well.
I'ld probably pull in the list of IDs for projects, but not the contents of said project, etc.

You don't want to do multiple queries like
"SELECT realname FROM authors WHERE authorid=foo"
"SELECT email FROM authors WHERE authorid=foo"...

It has to come down to some decisions on "heaviness" of instantiation and common use patterns.
Post Reply