473,387 Members | 1,481 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

References between nested objects (PHP4)

Hello

In a content administration tool I call classes from inside classes in order
to separate the admin functions from the display-only functions:

class book
{
var $title;
var $author;
var $adminfunctions;

function book($admin = false)
{
if ($admin) {
$this->adminfunctions =& new book_admin($this);
}
}

function display_book()
{
return $this->author.": ".$this->title;
}
}

class book_admin
{
var $boss;

function book_admin(&$boss)
{
$this->boss = $boss;
}

function update_book($author, $title)
{
$this->boss->author = $author;
$this->boss->title = $title;
}

[lots of other methods]
}

The admin code will be something like:

$book =& new book(true);
$book->adminfunctions->update_book("Michael Crichton", "Jurassic Parc");
echo $book->display_book();

As you see there is a circle reference, as book_admin::boss is a reference
back to book. I assume this is bad, and actually there are some problems
that I suspect are originated there.

Is there another possibility to access properties of the calling object? I
did not find any syntax similar to the parent::property syntax, and I can't
use inheritance, as there is already a vertical inheritance (such as page
extends book extends library...), and it is not possible to inherit two
classes.

Thanks for a hint!
Markus
Sep 5 '05 #1
13 3278
Reference is kinda kooky in PHP 4. I always try to dissuade people from
using it.

In the book_admin constructor, you need $this->boss =& $boss.
Otherwise the object will end up with a copy of its container.

Sep 6 '05 #2
> In a content administration tool I call classes from inside classes in order
to separate the admin functions from the display-only functions:

class book
{
var $title;
var $author;
var $adminfunctions;

function book($admin = false)
{
if ($admin) {
$this->adminfunctions =& new book_admin($this);
}
}

function display_book()
{
return $this->author.": ".$this->title;
}
}

class book_admin
{
var $boss;

function book_admin(&$boss)
{
$this->boss = $boss;
As Chung Leong pointed out you should probably change the line
above to

$this->boss =& $boss;

}

function update_book($author, $title)
{
$this->boss->author = $author;
$this->boss->title = $title;
}

[lots of other methods]
}

The admin code will be something like:

$book =& new book(true);
$book->adminfunctions->update_book("Michael Crichton", "Jurassic Parc");
echo $book->display_book();

As you see there is a circle reference, as book_admin::boss is a reference
back to book. I assume this is bad, and actually there are some problems
that I suspect are originated there.
Circular references are not something bad in general. Reference to "parent"
in a "child" and to "children" from "parent" are usually ok.

Is there another possibility to access properties of the calling object? I
did not find any syntax similar to the parent::property syntax, and I can't
use inheritance, as there is already a vertical inheritance (such as page
extends book extends library...), and it is not possible to inherit two
classes.


You are using some strange inheritance (as you described it, but it's not
in your example code). Book should not extend page, page should not extend
book. Book should contain pages (have references to them), page should (or
could) have reference to the book. Same with library and books. In your
scenario each page can be treated as a book or a library and each book can
be treated as a library. You should probably also not use inheritance
between book and book admin.
Hilarion
Sep 6 '05 #3
Chung Leong wrote:
Reference is kinda kooky in PHP 4. I always try to dissuade people
from using it.

In the book_admin constructor, you need $this->boss =& $boss.
Otherwise the object will end up with a copy of its container.


Thank you very much for this comment - this does indeed solve the problems I
had!

Anyway my goal is improving performance at the front end (implementing PEAR
Cache did a lot there), and I am not sure if separating the admin functions
is actually worth the effort. I would highly appreciate some quick comments
about this:

Existing structure: Class trees based on common base classes, such as:

- class common_functions
- class entity extends common_functions

- class rubric extends entity
- class page extends rubric

- class gallery extends entity

- class picture extends entity

Class common_functions contains some methods used for display and lots of
methods used for administration (such as string formatting, outputting form
fields and other stuff), and also integrates the database, language and
configuration objects.
Class entity controls the dependencies between it's sub-objects.
Class entity and it's subclasses all have 1 method for retrieving data and 3
methods for administration (create/update, duplicate, delete).

Thus, also for the front-end scripts all the administration methods are
loaded. So I thought of 2 possible levels of separation:

1. The admin methods are separated only from class common_functions and
integrated as a separate object. The $boss reference can be avoided there,
as those methods do either directly address the database or return values
instead of setting class properties. But the admin methods of the
sub-objects will still be loaded by the front-end scripts.

2. The admin methods are separated from all classes and build a separate
class tree:
- class entity_admin extends common_functions_admin
- class rubric extends entity_admin
and so on; the the main tree subclass constructor tells it's parents which
admin class has to be loaded.

I implemented solution 2 now and compared the execution times of the most
time-consuming front-end page (a gallery overview, creates 1 entity, rubric,
page and gallery object and 28 picture objects for the thumbnails). There is
no significant difference; it takes between 2.0 and 2.3 seconds[1] (without
caching of course). On the other side, the admin scripts run slower.

[1] Yes, I have some more ideas where to reduce server load...

So what I would like to know is: Does it make a significant difference if
only about 200 lines of code are loaded instead of about 1000 lines? Or is a
possible performance gain compensated by the more complex structure?
Now this has got a lot of text - if somebody takes his/her time to give me a
comment about it: Thanks a lot in advance!
Markus
Sep 6 '05 #4
Hilarion wrote:

As you see there is a circle reference, as book_admin::boss is a
reference back to book. I assume this is bad, and actually there are
some problems that I suspect are originated there.


Circular references are not something bad in general. Reference to
"parent" in a "child" and to "children" from "parent" are usually ok.


Thank you, I am happy to read this!
Is there another possibility to access properties of the calling
object? I did not find any syntax similar to the parent::property
syntax, and I can't use inheritance, as there is already a vertical
inheritance (such as page extends book extends library...), and it
is not possible to inherit two classes.


You are using some strange inheritance (as you described it, but it's
not in your example code). Book should not extend page, page should
not extend book. Book should contain pages (have references to them),
page should (or could) have reference to the book. Same with library
and books. In your scenario each page can be treated as a book or a
library and each book can be treated as a library. You should
probably also not use inheritance between book and book admin.


Yes I am sorry the example code was a poor example; I was quite tired and
annoyed when I wrote it. The classes actually behave the way you say they
should:

- common_functions
- entity extends common_functions
- "thing" extends entity

"Thing" will be the class to be actually instanciated, while some "things"
can have subclasses (as page extends rubric, because a page needs all the
properties and methods that a rubric has), and the relations between the
objects are handled at entity level via parent and order properties - thus
theoretically every kind of "thing" could be assigned to every other.

Thank you for your clarifications.

Markus
Sep 6 '05 #5
> Yes I am sorry the example code was a poor example; I was quite tired and
annoyed when I wrote it. The classes actually behave the way you say they
should:

- common_functions
- entity extends common_functions
- "thing" extends entity

"Thing" will be the class to be actually instanciated, while some "things"
can have subclasses (as page extends rubric, because a page needs all the
properties and methods that a rubric has),
Consider using common base class (eg. "document_fragment") for "rubric"
and "page" instead of inheritance between those.

and the relations between the
objects are handled at entity level via parent and order properties - thus
theoretically every kind of "thing" could be assigned to every other.


You should be more type-safe. I mean if the reference is always to an object
of specific class and is mostly used as the class, then you should make
sure, that it's always referred to as this class, not some base class.
Eg. you should use type hinting in PHP 5 and "instanceof" operator (in PHP 5)
or "is_a" function (in PHP 4 or 5).
Hilarion
Sep 6 '05 #6
Markus Ernst wrote:
Anyway my goal is improving performance at the front end (implementing PEAR
Cache did a lot there), and I am not sure if separating the admin functions
is actually worth the effort. I would highly appreciate some quick comments
about this:

Existing structure: Class trees based on common base classes, such as:

- class common_functions
- class entity extends common_functions

- class rubric extends entity
- class page extends rubric

- class gallery extends entity

- class picture extends entity


I'm an advocate for keeping things simple and obvious. Unless there's a
good reason to use inheritance, I generally avoid it. It's easier to
think that a book is a book, than a book being an extension of some
generalized, abstract object.

Sep 6 '05 #7
Chung Leong wrote:

I'm an advocate for keeping things simple and obvious. Unless there's
a good reason to use inheritance, I generally avoid it. It's easier to
think that a book is a book, than a book being an extension of some
generalized, abstract object.


Yes, this is a very useful guideline one sometimes tends to forget. Anyway
in this case the generalized abstract object is useful for handling the
relations between different things - i.e. a text element can be assigned to
a page, or to an author (biography), or to a book (abstract). A page can be
assigned to a rubric, or to an author (extended biography, works list...),
or to a book (review, excerpt...). Therefore I decided to use one
centralized ID and relations handling.
Sep 7 '05 #8
Hilarion wrote:

You should be more type-safe. I mean if the reference is always to an
object of specific class and is mostly used as the class, then you
should make sure, that it's always referred to as this class, not
some base class. Eg. you should use type hinting in PHP 5 and "instanceof"
operator
(in PHP 5) or "is_a" function (in PHP 4 or 5).


I see I got myself into some complicated things here and will have to spend
some more time with the manual :-)
Sep 7 '05 #9
Markus Ernst wrote:

Yes, this is a very useful guideline one sometimes tends to forget. Anyway
in this case the generalized abstract object is useful for handling the
relations between different things - i.e. a text element can be assigned to
a page, or to an author (biography), or to a book (abstract). A page can be
assigned to a rubric, or to an author (extended biography, works list...),
or to a book (review, excerpt...). Therefore I decided to use one
centralized ID and relations handling.


Markus,

But herein lies the problem. Inheritance is not applicable here. A
text element is not a "type of" a page. Rather, a page "contains" one
or more text elements.

A biography is a "type of" a book, so it would be applicable to derive
biography from book. The book also "has an" author, but the author is
not a "type of" text element (or vice versa).

Applying inheritance correctly can be quite complex - and I've seen it
misused quite a bit.

I use inheritance a fair amount. For instance - one I'm working on now
is for a non-profit. I have a hierarchy:

Person -> Member -> Board Member

Person includes non-members who have attended meetings and otherwise
shown an interest in the organization. Members are Persons with a
Member ID number and an expiration date. Board Member has the
additional attribute of Position.

Unfortunately, MySQL isn't an OO DB, so I need to fudge a little. I
could, for instance, put a Position column in the Persons table. But
that would end wasting space for those who are non-members.

So, I assign every person an internal ID (auto increment column). I
have a Members table with the ID, membership number which is linked to
the Person table. And a BoardMember table contains the ID and position.

The beauty of this is that all the work is hidden. If, for instance, I
want to send an email to everyone, I use a PersonList object. For
Members, a MemberList object, and Board Members I create a
BoardMemberList object. *All* the rest of the code to send the emails
is exactly the same. It's just a matter of which object I create. In
fact, the creation of the object is similar to:

switch($POST['mailto']) {
case 'All' :
$list=new PersonList();
break;
case 'Members':
$list = new MemberList();
break;
case 'Board':
$list = new BoardMemberList();
break;
default:
$emsg = 'No list selected';
break;
}
(rest of processing)

This is a perfect *applicable* use for inheritance.
--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
js*******@attglobal.net
==================
Sep 7 '05 #10
Jerry Stuckle wrote:

[...]
But herein lies the problem. Inheritance is not applicable here. A
text element is not a "type of" a page. Rather, a page "contains" one
or more text elements.

A biography is a "type of" a book, so it would be applicable to derive
biography from book. The book also "has an" author, but the author is
not a "type of" text element (or vice versa).


[...]

Thank you for your detailled and understandable example! If I understand
everything correctly, my problem is rather to make myself understandable (I
am not a native English speaker and not an educated IT professional either,
so I may have chosen the wrong words and also poor or too much simplified
examples). I did the following classes (each of which has a corresponding
MySQL table):

entity -> rubric -> page [1]
entity -> contents element (such as text or picture or text and picture...)
entity -> product category
entity -> product -> book
entity -> product -> cd
entity -> product -> postcard
entity -> author
....

The main properties of entity are id, parent, active/inactive and sort
order. So for all kinds of common tasks - handle sort order,
activate/deactivate display... - I have one method at entity level, and I
can flexibly handle all kinds of 1:n relations at entity level by assigning
the id value of one object to the parent value of another one, regardless of
what type the objects are of.
So I can assign a page not only to a rubric (which is the natural container
for pages), but also for example to an author. Or assign a text element not
only to a page (which is the natural container for text elements), but also
to an author. Like that I can reduce the author data record to the very
basic - name, picture, contact information... - and still freely add
additional info where appropriate.
Of course n:m relations such as the product/author relation are handled
separately.

[1] I assume that the rubric -> page inheritance in my example (and the
wrong book -> page example in my original posting) made the impression that
I used inheritance for every kind of relations. Though it is true that a
page is not a type of a rubric, this seemed useful to me as below a parent
rubric there can be pages and sub-rubrics mixed. Thus specially the sort
order handling and menu composition would be very complicated if pages and
rubrics were handled separately.
My original question was about how to include the methods needed for
administration only in order to reduce server load at the front end.
Actually entity inherited a class with lots of admin methods:

common functions -> entity -> ...

And also every class contains specialized admin functions; for example in
the postcard class the method delete_postcard() will delete the postcard
record and then call $this->delete_product(), which will delete the product
record and call $this->delete_entity().

So now I separated the admin methods into separate classes that are not
inherited but only called when they are needed.

Markus
Sep 8 '05 #11
> entity -> rubric -> page [1]
entity -> contents element (such as text or picture or text and picture...)
Why not something like that:

entity -> contents element -> rubric
entity -> contents element -> page
entity -> product category
entity -> product -> book
entity -> product -> cd
entity -> product -> postcard
entity -> author
...

The main properties of entity are id, parent, active/inactive and sort
order. So for all kinds of common tasks - handle sort order,
activate/deactivate display... - I have one method at entity level, and I
can flexibly handle all kinds of 1:n relations at entity level by assigning
the id value of one object to the parent value of another one, regardless of
what type the objects are of.
Do you need such general way of referencing? If you do not know the nature
of referenced entities, then the reference is (almost) useless.
So I can assign a page not only to a rubric (which is the natural container
for pages), but also for example to an author.
To assign rubric as a part of page you should build collection "visually contains"
of content elements in content element class.

Or assign a text element not only to a page (which is the natural container
for text elements),
As above.

but also to an author.
What for? If the text has an author, then make "author" property in content
element class (from which text element should probably be derived).

Like that I can reduce the author data record to the very
basic - name, picture, contact information... - and still freely add
additional info where appropriate.
By the ways above you could also do it, but without mixing things.

Of course n:m relations such as the product/author relation are handled
separately.

[1] I assume that the rubric -> page inheritance in my example (and the
wrong book -> page example in my original posting) made the impression that
I used inheritance for every kind of relations. Though it is true that a
page is not a type of a rubric, this seemed useful to me as below a parent
rubric there can be pages and sub-rubrics mixed. Thus specially the sort
order handling and menu composition would be very complicated if pages and
rubrics were handled separately.
Why do not do it on contents element level? This way many content elements
could have subelements. You could also make more levels of inheritance
by doing it like this:

entity -> contents element -> text element
entity -> contents element -> contents collector -> rubric
entity -> contents element -> contents collector -> page

And create "visually contains" collection of contents elements in contents
collector class and this way separate simple elements (which do not
contain other elements) from complex elements (like rubrics or pages).
The ordering mechanisms would appear in the collection (so on contents
collector class) and rendering mechanisms in contents element class.

My original question was about how to include the methods needed for
administration only in order to reduce server load at the front end.
Actually entity inherited a class with lots of admin methods:

common functions -> entity -> ...

And also every class contains specialized admin functions; for example in
the postcard class the method delete_postcard() will delete the postcard
record and then call $this->delete_product(), which will delete the product
record and call $this->delete_entity().

So now I separated the admin methods into separate classes that are not
inherited but only called when they are needed.


That should be a bit better. The administrative hierarchy could be
related to logical hierarchy (class responsible for persistance of rubric
class could inherit from class responsible for persistance of contents
collector class or it could contain reference to instance of such class).
Hilarion
Sep 8 '05 #12
Markus Ernst wrote:
Jerry Stuckle wrote:

Thank you for your detailled and understandable example! If I understand
everything correctly, my problem is rather to make myself understandable (I
am not a native English speaker and not an educated IT professional either,
so I may have chosen the wrong words and also poor or too much simplified
examples).
Not a problem. Your English is excellent - much better than many
Americans! No problem with your terminology, either. The problem here
is that proper inheritance hierarchies are not easy.

I did the following classes (each of which has a corresponding MySQL table):

entity -> rubric -> page [1]
entity -> contents element (such as text or picture or text and picture...)
entity -> product category
entity -> product -> book
entity -> product -> cd
entity -> product -> postcard
entity -> author
...
[...]

[1] I assume that the rubric -> page inheritance in my example (and the
wrong book -> page example in my original posting) made the impression that
I used inheritance for every kind of relations. Though it is true that a
page is not a type of a rubric, this seemed useful to me as below a parent
rubric there can be pages and sub-rubrics mixed. Thus specially the sort
order handling and menu composition would be very complicated if pages and
rubrics were handled separately.

But here is the problem. "A page is not a type of a rubric", so
inheritance is not appropriate. It may make things easier now, but can
cause problems in the long run.

The problem here is you need *some* relationship between "page" and
"rubric" - that is, they have some common data and methods (functions).
However, a "page" will not necessarily have ALL data and methods,
which would be true if you had a real "is-a" relationship.

Hilarion has the right idea. What you need is another level of
inheritance. Take the methods and data which are common to "page" and
"rubric" and extract them to "contents_element". That way you can
derive both "rubric" and "page" from "contents_element". Both will be
of the "contents_element" type, but there will not be a direct
relationship between the two.

My original question was about how to include the methods needed for
administration only in order to reduce server load at the front end.
Actually entity inherited a class with lots of admin methods:

common functions -> entity -> ...

And also every class contains specialized admin functions; for example in
the postcard class the method delete_postcard() will delete the postcard
record and then call $this->delete_product(), which will delete the product
record and call $this->delete_entity().

So now I separated the admin methods into separate classes that are not
inherited but only called when they are needed.

Markus


You can separate them into different classes, but that will cause a lot
of duplication of work - if, for instance, you change your database,
you'll have twice as many classes which need to be updated, which is a
lot of what OO tries to avoid.

My first question is - do you really have a server load problem? What
is your CPU utilization? I suspect it's pretty low - few sites I've
seen average even 20-30% CPU over a one minute period during peak times.
And if you're going over 50% regularly, you probably need a faster
server anyway.

My point here is - parsing PHP code is generally pretty fast, especially
in respect to some operations like searching a database. If you are
having performance problems, it's time to look at the code to see how
you can optimize it better. Putting admin functions in another file
just won't save you much time (unless you have tens of thousands of
lines of code - and even then you won't save much).
--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
js*******@attglobal.net
==================
Sep 9 '05 #13
Jerry Stuckle wrote:

My point here is - parsing PHP code is generally pretty fast,
especially in respect to some operations like searching a database. If you
are having performance problems, it's time to look at the code
to see how you can optimize it better. Putting admin functions in
another file just won't save you much time (unless you have tens of
thousands of lines of code - and even then you won't save much).


Thank you - this is really good to know, as it helps deciding where to look
for optimization potential.

I highly appreciate your input as well as Hilarion's and Chung's, they
helped me gain a better understanding of OO and improve my work.

--
Markus
Sep 20 '05 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
by: PIII450 | last post by:
Hi all, I have a system running IIS en Apache. It is also running ASP and PHP. Why would <% Dim obj1 Dim var1
5
by: Jan Pieter Kunst | last post by:
(apologies if this message is a duplicate -- my news server seems to have problems) Greetings, When using PHP 4, this: // ex. 1 class A { function A(&$obj) {
29
by: Tim Clacy | last post by:
Am I correct in think that you can't re-assign a reference to a different object? If so, what should happen here: struct A { DoSomeThing(); }; A& GetNextA();
8
by: Eric Eggermann | last post by:
I'm having a problem with really large file sizes when serializing the classes that describe my little document. There are some circular references which result in the same object getting written...
37
by: Tim N. van der Leeuw | last post by:
Hi, The following might be documented somewhere, but it hit me unexpectedly and I couldn't exactly find this in the manual either. Problem is, that I cannot use augmented assignment operators...
28
by: Frederick Gotham | last post by:
When I was a beginner in C++, I struggled with the idea of references. Having learned how to use pointers first, I was hesitant to accept that references just "do their job" and that's it. Just...
3
by: howa | last post by:
according to the php manual, it said: Do not use return-by-reference to increase performance, the engine is smart enough to optimize this on its own. I doubt if this only apply to the PHP5...
2
by: amygdala | last post by:
I'm trying to figure out the correct use of references. Lets say I have a class Validator and a class User. And I want to let a User instance be an referenced object in Validator. Where would the...
4
by: Ronald Raygun | last post by:
I want to store objects in ana array and then iterate through the array, retrieving a (reference) to each object in the array, and calling a method on the array. I am not sure how to do it, but...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.