SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 37
  1. #1
    ********* obeah makeda's Avatar
    Join Date
    Jun 2001
    Location
    rollin' on dubs
    Posts
    492
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    inheritance with different constructors

    This question is regarding a class inheriting from another class and how you handle the constructors in PHP. I have a DataBase class which handles all my DB stuff. His constructor takes username and password:

    Code:
    class DB {
      function DB($user,$pass) {
        //does stuff here
      }
    }
    Now, I want to write a new class for a guestbook and he needs to access the db so I want him to inherit my db class BUT I also want to give him his own constructor, let say that it looks like this:

    Code:
    class GBook extends DB {
      function GBook($entry) {
        //do stuff here
      }
    }
    So, first of all, is it possible to have separate constructors like this and if so, how do I instantiate the child class (GBook)?

  2. #2
    SitePoint Wizard Chris82's Avatar
    Join Date
    Mar 2002
    Location
    Osnabrück
    Posts
    1,003
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You cannot use the same name for a method / constructor with different arguments.

    You can use func_num_args() and func_get_arg(x) to somewhat mimic multiple constructors with different arguments.

    However, wouldn't it be a better idea to pass the DB object to the GuestBook or maybe use several classes for a file based and db based Guestbook such as:

    Code:
    <?php
    class GuestBook
    {
       var $data;
    
       function GuestBook(&$data)
       {
          $this->data =& $data;
       }
    
       function addEntry()
       {
          die ('abstract');
       }
    
        function getNumberOfEntries()
        {
            $this->data->getTotal();
        }
    
       // other common functions here
    }
    
    class DBGuestBook extends GuestBook
    {
       // pass a DB object in the constructor
       
       function addEntry($entry)
       {
          $this->data->query("INSERT INTO foo (bar, baz) VALUES ({$entry[0]}, {$entry[1]})");
       }
    }
    
    class FileGuestBook extends GuestBook
    {
       // pass a file object in the constructor
       
       function addEntry($entry)
       {
          $this->data->write($entry[0] . '|' . $entry[1]);
       }
    }
    
    ?>

  3. #3
    ********* obeah makeda's Avatar
    Join Date
    Jun 2001
    Location
    rollin' on dubs
    Posts
    492
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Chris382, thanks for the response!

    I think i'm going to do the same thing only in reverse. I am going to leave the db constructor and lose the GBook constructor, choosing instead to set my GBook properties on their own.

    What prompted my question is that I've been writing some .Net apps lately and I know that you can do this with C#. I wasn't sure if you could with php as well.

  4. #4
    As the name suggests... trickie's Avatar
    Join Date
    Jul 2002
    Location
    Melbourne, Australia
    Posts
    678
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The answer to yuor original question is yes, the Guestbook class can have it's own constructor. You can even call the parent class' constructor (in this case DB) from within the Guestbook constructor.

    PHP Code:
    class GuestBook extends DB
    {
       function 
    GuestBook()
       {
          
    parent:: DB();   
       }


    I think that from a design point of view it might be better to leave the DB class and the Guestbook class seperate, and pass the DB as a instance variable of the guestbook. This would allow later seperation.

  5. #5
    ********* obeah makeda's Avatar
    Join Date
    Jun 2001
    Location
    rollin' on dubs
    Posts
    492
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Cool, thanks Trickie. And as an edit to what I said before, I have now eliminated the constructor for my DB class and just created a separate method to set the parameters.

    But to the point that you both raised, I don't think I'm understanding what you're saying. If i have a generic dbclass and my GBook class inherits from it, what is the drawback to that? The db layer is totally abstracted, isn't it?

  6. #6
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Inheritance is usually depicted as an 'IS-A' relationship. (A Porsche is a car, so class Porsche extends Car). In your case this is not true, because a guestbook is not a database connection; it merely uses one.

    The most important drawback is that your script might now require multiple database connections. You have a Guestbook class ('is-a' Database) and a User class ('is-a' Database as well?) and as both classes are instantiated seperately, they will both use a different database connection. It makes much more sense to do something like this:

    PHP Code:
    class Guestbook {
        var 
    $db;
        function 
    Guestbook(&$db) {
            
    $this->db =& $db;
        }
    }

    class 
    User {
        var 
    $db;
        function 
    User(&$db) {
            
    $this->db =& $db;
        }
    }

    $db =& new Database('username''password');
    $guestbook =& new Guestbook($db);
    $user =& new User($db); 
    Now both the Guestbook class and the User class re-use the same database connection. Also, their 'is-a' relationship with the Database is now gone, which makes a lot more sense.

    Vincent

  7. #7
    ********* Wizard silver trophy Cam's Avatar
    Join Date
    Aug 2002
    Location
    Burpengary, Australia
    Posts
    4,495
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    Tricky, what does parent :: DB() do? Since GBook extends DB doesn't it automatically know that DB is the parent or am I completely lost??

  8. #8
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm not Tricky (or maybe I am... ) but I can answer this question too.

    When you write a subclass of some class, you have to call its constructor in the constructor of the subclass. This is not done automatically (see the PHP reference manual). Tricky does it like this:

    PHP Code:
    class extends {
        function 
    B() {
            
    parent::A(); // parent constructor
        
    }

    However, for some reason I don't like this construction at all (just a feeling), so I always do this:

    PHP Code:
    class extends {
        function 
    B() {
            
    $this->A(); // parent constructor
        
    }

    To me this makes more sense. But again, it's just a feeling .

    Anyway, I don't think it matters much what you do; both ways of doing it have the same (correct) result.

    Vincent

  9. #9
    ********* obeah makeda's Avatar
    Join Date
    Jun 2001
    Location
    rollin' on dubs
    Posts
    492
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Wow, all great points. Thanks. I think I'm going to do as you suggested and just pass in an instance of my dbObject. Since I won't be inheriting from it anymore, i'll give him back his constructor.

  10. #10
    Sidewalking anode's Avatar
    Join Date
    Mar 2001
    Location
    Philadelphia, US
    Posts
    2,205
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hm...when one is calling the parent constructor from the child constructor, does the child constructor need to declare all of the variables declared in the parent? For example
    PHP Code:
    class Foo {
    var 
    $a;
    function 
    Foo ($a) {
            
    $this->$a;
    }
    }
    class 
    FooBar extends Foo {
    var 
    $b;
    function 
    FooBar($b) {
            
    $this->Foo($a);
            
    $this->$b;
    }

    or
    PHP Code:
    class Foo {
    var 
    $a;
    function 
    Foo ($a) {
            
    $this->$a;
    }
    }
    class 
    FooBar extends Foo {
    var 
    $a;
    var 
    $b;
    function 
    FooBar($a$b) {
            
    $this->Foo($a);
            
    $this->$b;
    }

    Last edited by anode; Jan 21, 2003 at 22:19.

  11. #11
    ********* Wizard silver trophy Cam's Avatar
    Join Date
    Aug 2002
    Location
    Burpengary, Australia
    Posts
    4,495
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    Ahhh, I understand now I would use parent::A() because it looks cooler

  12. #12
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hm...when one is calling the parent constructor from the child constructor, does the child constructor need to declare all of the variables declared in the parent?
    No - these are also inherited. The child is able to talk directly to the parents variables.

    For example;

    PHP Code:
    class Parent {
        var 
    $foo;
        function 
    Parent () {
            
    $this->foo='Hello World!';
        }

    }

    class 
    Child {
        function 
    Child () {
            
    Parent::Parent();
        }
        function 
    displayFoo () {
            echo ( 
    $this->foo ); // Displays 'Hello World!'
        
    }


  13. #13
    Sidewalking anode's Avatar
    Join Date
    Mar 2001
    Location
    Philadelphia, US
    Posts
    2,205
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for clearing that up, Harry. I have to say it's a bit counterintuitive.

    Any difference other than aesthetic between "::" and "->"?

  14. #14
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    With parent variables the same is true in other languages, like Java. Of course in Java you can protect variables so children can't access them.

    Any difference other than aesthetic between "::" and "->"?
    In general :: is used to run a class method without instantiating the entire class as an object.

    So you could have;

    PHP Code:
    class MyClass {
        function 
    MyClass () {
            echo ( 
    'This is the constructor' );
        }
        function 
    someFunc () {
            echo ( 
    'This is someFunc' );
        }
    }

    MyClass::someFunc(); // Displays 'This is someFunc'

    $myClass=new MyClass// Displays 'This is the constructor'
    $myClass->someFunc(); // Displays 'This is someFunc' 
    With children calling parents it's kind of a special case where because the class scope is correct, the parent constructor "does the right thing".

    Vincent definately does have a point. Trouble is with PHP 5.0 all constructors will have the same name. I'm still not sure if I like that - not sure it's a real benefit - the justification is it makes rename your classes less work.

  15. #15
    ********* wombat firepages's Avatar
    Join Date
    Jul 2000
    Location
    Perth Australia
    Posts
    1,717
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by voostind
    When you write a subclass of some class, you have to call its constructor in the constructor of the subclass. This is not done automatically (see the PHP reference manual). Tricky does it like this:
    Isn't that the other way around ? , thats how it used to work in PHP3 , 4 should be different ?

    PHP Code:
    <?
    class yak 

       function 
    yak() 
       { 
           echo 
    "i'm a yak...<br />\n"
       } 
       function 
    doubt(){
        echo 
    "but with reservations~<br />\n";
       }


    class 
    llama extends yak 

       function 
    wombat() 
       { 
           echo 
    "now i'm a llama.....<br />\n"
           
    $this->doubt();
       } 



    $yak = new llama
    $yak->wombat();
    ?>
    unless we are on about totally different things.

  16. #16
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    unless we are on about totally different things.
    We are

    I was talking about constructors, not general methods...

    Vincent

  17. #17
    ********* wombat firepages's Avatar
    Join Date
    Jul 2000
    Location
    Perth Australia
    Posts
    1,717
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ok - but in the above, does a call to new llama() not call the yak constructor automatically ?

    I am not harping on BTW just trying to get on the same wavelength (if not the same plane )

  18. #18
    Sidewalking anode's Avatar
    Join Date
    Mar 2001
    Location
    Philadelphia, US
    Posts
    2,205
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Firepages:that's what got me confused in the first place4; I read somewhere that it doesn't.


    Hey OOP Superstars: you know what would be really awesome and educational? An intensive SitePoint OOP clinic over IRC. Pleeease. <bats eyelashes>

  19. #19
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ok - but in the above, does a call to new llama() not call the yak constructor automatically ?
    I was going to say no, but then I looked at your code, and now I have changed my mind: yes.

    In your case, a $llama = new llama; will indeed automatically call the constructor of class yak (the parent class). However, this is only true because class llama itself has no constructor. As soon as you write one, then you'll have to call yak() yourself:

    PHP Code:
    class llama extends yak {
        function 
    llama() {
            
    $this->yak();
            
    // or: parent::yak();
        
    }

    When I implement a class, I always write a constructor function, even when it is empty. When I write a subclass, I always add a call to the parent constructor (which could be empty). This ensures I won't run into weird behavior when I decide to change my code in one way or another. Call it a safety mechanism.

    I am not harping on BTW just trying to get on the same wavelength
    I think I figured out where the confusion came from...

    Vincent

  20. #20
    ********* wombat firepages's Avatar
    Join Date
    Jul 2000
    Location
    Perth Australia
    Posts
    1,717
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think I figured out where the confusion came from...
    lol same here

    I always use a constructor as well, I recall sometimes, not needing one but getting nervous about it and making one anyway

  21. #21
    SitePoint Addict
    Join Date
    May 2001
    Posts
    217
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Warning : This might be offtopic but the question just crossed my mind

    When passing an object into a class as a refrence (objectA), doesnt the original objects (objectA) methods/variables get changed in all the classes it was passed to? Or how does that work?

    -unregistered.

  22. #22
    SitePoint Wizard samsm's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta, GA, USA
    Posts
    5,011
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by unregistered
    When passing an object into a class as a refrence (objectA), doesnt the original objects (objectA) methods/variables get changed in all the classes it was passed to? Or how does that work?
    No, objectA keeps it's own methods and variables. When it is passed into a class method or object method it retains all of its characteristics.

    That means you can write code like this:
    PHP Code:
    class exampleB
    {
       function 
    exampleB($objectA)
       {
          return 
    $objectA->doSomething();
       }

    ...where you access a method of an object through another object's method.
    Using your unpaid time to add free content to SitePoint Pty Ltd's portfolio?

  23. #23
    Super Ninja Monkey Travis's Avatar
    Join Date
    Dec 2001
    Location
    Sioux City, Iowa
    Posts
    691
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yes but what about this?
    PHP Code:
    class Test {
        var 
    $a;
        function 
    Test ($a) {
            
    $this->$a;
        }

        function 
    set_a ($a) {
            
    $this->$a;
        }

        function 
    output_a () {
            if (
    $a == 1) {
                echo 
    $a '= 1!';
            }

            else {
                echo 
    $a '!= 1!';
            }
    }

    class New {
        function New (
    $test) {
              
    $this->test->set_a (1);
        }
    }

    class 
    New2 {
        function 
    New2 ($test) {
            
    $this->test->output_a ();
        }
    }

    $test = new Test (1);
    $new = new New ($test);
    $new2 = new New2 ($test); 
    What would the output be? I can't test it right now.
    Travis Watkins - Hyperactive Coder
    My Blog: Realist Anew
    Projects: Alacarte - Gnome Menu Editor

  24. #24
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by Trav
    What would the output be?
    "Call to undefined method..."

    It's close but you haven't assigned the instance of $test to a local variable your New classes. Also it's good practice to pass by reference.

    Finally in Test the output() method doesn't use the local variable (have modified that)

    You also need references (have added) to make sure New and New1 both work on the same instance of Test

    So this would give you what you want...

    PHP Code:
    class Test {
        var 
    $a;
        function 
    Test ($a) {
            
    $this->$a;
        }

        function 
    set_a ($a) {
            
    $this->$a;
        }

        
    // Modified to use $this->a
        
    function output_a () {
            if (
    $this->== 1) {
                echo 
    $this->'= 1!';
            }

            else {
                echo 
    $this->'!= 1!';
            }
    }

    class New {
        var 
    $test;
        function New (& 
    $test) {
              
    $this->test=& $test// Assign to local member
              
    $this->test->set_a (1);
        }
    }

    class 
    New2 {
        var 
    $test;
        function 
    New2 (& $test) {
            
    $this->test=& $test;
            
    $this->test->output_a ();
        }
    }

    $test = new Test (1);
    $new = new New ($test);
    $new2 = new New2 ($test); 
    That should give;

    1=1!

    Note also you could have done this;

    PHP Code:
    class New {
        function New (& 
    $test) {
              
    $test->set_a (1); // Call $test->set_a() from local scope
        
    }

    Last edited by HarryF; Jan 23, 2003 at 09:51.

  25. #25
    Super Ninja Monkey Travis's Avatar
    Join Date
    Dec 2001
    Location
    Sioux City, Iowa
    Posts
    691
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah I was rushed and didn't have time to make sure everything was right. So if I don't pass by reference what would the output be? It would consider each class to have a copy of Test instead of a reference to the original, wouldn't it?
    Travis Watkins - Hyperactive Coder
    My Blog: Realist Anew
    Projects: Alacarte - Gnome Menu Editor


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •