References between nested objects (PHP4)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Markus Ernst

    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->adminfunctio ns =& new book_admin($thi s);
    }
    }

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

    class book_admin
    {
    var $boss;

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

    function update_book($au thor, $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->adminfunctio ns->update_book("M ichael Crichton", "Jurassic Parc");
    echo $book->display_book() ;

    As you see there is a circle reference, as book_admin::bos s 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::propert y 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


  • Chung Leong

    #2
    Re: References between nested objects (PHP4)

    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.

    Comment

    • Hilarion

      #3
      Re: References between nested objects (PHP4)

      > In a content administration tool I call classes from inside classes in order[color=blue]
      > 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->adminfunctio ns =& new book_admin($thi s);
      > }
      > }
      >
      > function display_book()
      > {
      > return $this->author.": ".$this->title;
      > }
      > }
      >
      > class book_admin
      > {
      > var $boss;
      >
      > function book_admin(&$bo ss)
      > {
      > $this->boss = $boss;[/color]

      As Chung Leong pointed out you should probably change the line
      above to

      $this->boss =& $boss;

      [color=blue]
      > }
      >
      > function update_book($au thor, $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->adminfunctio ns->update_book("M ichael Crichton", "Jurassic Parc");
      > echo $book->display_book() ;
      >
      > As you see there is a circle reference, as book_admin::bos s is a reference
      > back to book. I assume this is bad, and actually there are some problems
      > that I suspect are originated there.[/color]

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

      [color=blue]
      > Is there another possibility to access properties of the calling object? I
      > did not find any syntax similar to the parent::propert y 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.[/color]

      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

      Comment

      • Markus Ernst

        #4
        Re: References between nested objects (PHP4)

        Chung Leong wrote:[color=blue]
        > 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.[/color]

        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_function s
        - class entity extends common_function s

        - class rubric extends entity
        - class page extends rubric

        - class gallery extends entity

        - class picture extends entity

        Class common_function s 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_function s 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_function s_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


        Comment

        • Markus Ernst

          #5
          Re: References between nested objects (PHP4)

          Hilarion wrote:[color=blue][color=green]
          >>
          >> As you see there is a circle reference, as book_admin::bos s is a
          >> reference back to book. I assume this is bad, and actually there are
          >> some problems that I suspect are originated there.[/color]
          >
          > Circular references are not something bad in general. Reference to
          > "parent" in a "child" and to "children" from "parent" are usually ok.[/color]

          Thank you, I am happy to read this!
          [color=blue][color=green]
          >> Is there another possibility to access properties of the calling
          >> object? I did not find any syntax similar to the parent::propert y
          >> 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.[/color]
          >
          > 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.[/color]

          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_function s
          - entity extends common_function s
          - "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


          Comment

          • Hilarion

            #6
            Re: References between nested objects (PHP4)

            > Yes I am sorry the example code was a poor example; I was quite tired and[color=blue]
            > annoyed when I wrote it. The classes actually behave the way you say they
            > should:
            >
            > - common_function s
            > - entity extends common_function s
            > - "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),[/color]

            Consider using common base class (eg. "document_fragm ent") for "rubric"
            and "page" instead of inheritance between those.

            [color=blue]
            > 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.[/color]

            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

            Comment

            • Chung Leong

              #7
              Re: References between nested objects (PHP4)

              Markus Ernst wrote:[color=blue]
              > 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_function s
              > - class entity extends common_function s
              >
              > - class rubric extends entity
              > - class page extends rubric
              >
              > - class gallery extends entity
              >
              > - class picture extends entity[/color]

              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.

              Comment

              • Markus Ernst

                #8
                Re: References between nested objects (PHP4)

                Chung Leong wrote:[color=blue]
                >
                > 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.[/color]

                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.


                Comment

                • Markus Ernst

                  #9
                  Re: References between nested objects (PHP4)

                  Hilarion wrote:[color=blue]
                  >
                  > 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).[/color]

                  I see I got myself into some complicated things here and will have to spend
                  some more time with the manual :-)


                  Comment

                  • Jerry Stuckle

                    #10
                    Re: References between nested objects (PHP4)

                    Markus Ernst wrote:[color=blue]
                    >
                    > 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.
                    >
                    >[/color]

                    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.
                    jstucklex@attgl obal.net
                    =============== ===

                    Comment

                    • Markus Ernst

                      #11
                      Re: References between nested objects (PHP4)

                      Jerry Stuckle wrote:

                      [...]
                      [color=blue]
                      > 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).[/color]

                      [...]

                      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


                      Comment

                      • Hilarion

                        #12
                        Re: References between nested objects (PHP4)

                        > entity -> rubric -> page [1][color=blue]
                        > entity -> contents element (such as text or picture or text and picture...)[/color]

                        Why not something like that:

                        entity -> contents element -> rubric
                        entity -> contents element -> page
                        [color=blue]
                        > 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.[/color]

                        Do you need such general way of referencing? If you do not know the nature
                        of referenced entities, then the reference is (almost) useless.
                        [color=blue]
                        > 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.[/color]

                        To assign rubric as a part of page you should build collection "visually contains"
                        of content elements in content element class.

                        [color=blue]
                        > Or assign a text element not only to a page (which is the natural container
                        > for text elements),[/color]

                        As above.

                        [color=blue]
                        > but also to an author.[/color]

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

                        [color=blue]
                        > 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.[/color]

                        By the ways above you could also do it, but without mixing things.

                        [color=blue]
                        > 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.[/color]

                        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.

                        [color=blue]
                        > 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.[/color]

                        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

                        Comment

                        • Jerry Stuckle

                          #13
                          Re: References between nested objects (PHP4)

                          Markus Ernst wrote:[color=blue]
                          > 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).[/color]

                          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[color=blue]
                          > 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
                          > ...
                          >[/color]
                          [...]
                          [color=blue]
                          >
                          > [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.
                          >[/color]

                          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_eleme nt". That way you can
                          derive both "rubric" and "page" from "contents_eleme nt". Both will be
                          of the "contents_eleme nt" type, but there will not be a direct
                          relationship between the two.
                          [color=blue]
                          >
                          > 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
                          >
                          >[/color]

                          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.
                          jstucklex@attgl obal.net
                          =============== ===

                          Comment

                          • Markus Ernst

                            #14
                            Re: References between nested objects (PHP4)

                            Jerry Stuckle wrote:[color=blue]
                            >
                            > 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).[/color]

                            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


                            Comment

                            Working...