SitePoint Sponsor

User Tag List

Results 1 to 14 of 14
  1. #1
    SitePoint Wizard samsm's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta, GA, USA
    Posts
    5,011
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    My beginner OOP questions

    Ok, I'm starting to get the hang of making objects and classes in PHP however I have some beginner questions ... here's one of them!

    Can you 'extend' and object? Here's what I mean: Lets say you have a 'person' class and a 'student' class that extends 'person'. If you created an object:
    $sam = new person;
    You wouldn't have access to the 'student' methods. I appriciate the benefits of that fact but is there a way to alter $sam from above so that it was a student and not just a person?
    In other words make it as if this was done originally:
    $sam = new student;

    Thanks for reading!
    Sam
    Using your unpaid time to add free content to SitePoint Pty Ltd's portfolio?

  2. #2
    Ribbit... Eric.Coleman's Avatar
    Join Date
    Jun 2001
    Location
    In your basement
    Posts
    1,268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yes You Can.

    Example:

    PHP Code:
    <?php
    class person
    {
        var 
    $name;
        
        function 
    setVar($name$value)
        {
            
    $this->$name $value;
        }
    }
    class 
    student extends person
    {
        function 
    printStudentName()
        {
            echo 
    $this->name;
        }
    }
    $sam = new student;
    $sam->setVar('name''Sam');
    $sam->printStudentName();
    ?>
    Eric Coleman
    We're consentratin' on fallin' apart
    We were contenders, now throwin' the fight
    I just wanna believe, I just wanna believe in us

  3. #3
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I don't think that was what samsm meant. He already knows how to create a subclass, but he wants to know if he can dynamically change an object to another one, like this:

    PHP Code:
    class Person { ... }
    class 
    Student extends Person { ... }

    $sam = new Person();
    $samAsStudent = (Student)$sam;
    $samAsStudent->studentMethod(); 
    The answer to that question is (I think): no. The reason for that is very simple if you think about it for a while. Class Student extends class Person, or in other words: class Student adds properties to class Person. If you have an object of class Person, it doesn't have the additional properties of a Student. So what should the system (PHP) do? Invent them? Say class Student adds a property 'school' which can be retrieved by calling the method 'getSchool()' on a Student object. If you would be able to make a Person into a Student, what should that method return?

    Now, my question to you, samsm, would be: why would you want to do this? If you think it is necessary to be able to do this, you don't know enough about object-oriented programming yet. (No disrespect intended!)

    Also, I would like to comment on some code of Zaire:

    PHP Code:
    function setVar($name$value)
    {
        
    $this->$name $value;

    Code like this is extremely bad! Sadly enough I have seen that some PEAR-programmers are actually advocating it, but it's a bad idea for many reasons:
    - You require application programmers to have an intimate knowledge of the internals of your class. If you have an internal property 'name' and you want users of your class to be able to set it, they must first now it's actually there! In terms of 'encapsulation', or 'information hiding' that's a very bad idea. You don't want your class users to know HOW the class works; they should only need to know WHAT it does, like a black box.
    - What if you need to execute additional code when some property is set? If you had a method like 'setName($name)', you could use that method to do that. You might not need to do that know, but who knows about the future?
    - What if you need to rename (or add or delete) class variables sometime in the future, because you thought of a better, more efficient way to achieve the same result? Doing that will most likely break existing code, which wouldn't be the case had you used proper 'set...'-methods.
    - You explicitly allow application programmers to influence the internals of your object. You not only allow users to set 'public properties' without you knowing about it, you also allow them to set internal class variables you don't want them to access, or add variables that weren't originally there.

    So whatever somebody (e.g. a PEAR developer) told you about it being a good idea: forget about it, because it's not! ALWAYS aim for full encapsulation (meaning NO public class variables), because it will save your life in the long run. I know the well-respected PHP-developer Stig Bakken doesn't fully agree with me on this point (to quote him: "I'm not in the 'encapsulate or die' camp") but then he's just a human being like the rest of us, so he doesn't know everything. Just trust me on this one...

    Vincent

  4. #4
    Ribbit... Eric.Coleman's Avatar
    Join Date
    Jun 2001
    Location
    In your basement
    Posts
    1,268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Heh..

    I know that was bad code, I don't even use that myself..

    Then again, most of my classes are private only so it Doesn't really matter to me ;P
    Eric Coleman
    We're consentratin' on fallin' apart
    We were contenders, now throwin' the fight
    I just wanna believe, I just wanna believe in us

  5. #5
    SitePoint Wizard samsm's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta, GA, USA
    Posts
    5,011
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Vincent is right, Zaire... his was the answer I was looking for. Thanks to both of you for responding though .


    I am fairly new to programming and very new to OOP so I appriciate all the help I can get.... do my best not tro get in bad habits from the get go.

    If you have an object of class Person, it doesn't have the additional properties of a Student. So what should the system (PHP) do? Invent them?
    I was thinking that in order for it to be valid one would have to add the needed properties at the time of "extending" the object..... so perhaps my concept of OOP isn't as woeful as it might have sounded .

    However, knowing that that is not done pushes me in the right direction. I'll play around with the stuff tomorrow and perhaps generate some more questions.

    Thanks!
    Sam
    Using your unpaid time to add free content to SitePoint Pty Ltd's portfolio?

  6. #6
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    There is an important difference between 'classes' and 'objects'. You might not be familiar with this difference, since you wondered how you could extend objects.

    Classes are the blueprints for objects, and in that sense they are very static. Once a class is successfully written it doesn't change anymore, even though applications might use it for a variety of reasons. A class defines how an object can be constructed, and that's that.

    Objects are instances of some class. They are dynamic things you can change by calling methods on them, passing them to other objects or putting other objects inside them. Although it's hard to say beforehand exactly what your objects will do and how they will work together, each object has a specific, non-changing structure, defined by its blueprint: the class.

    When you instantiate an object for some class, all you need is one simple line: '$sam = new Person'. That's all. In reality you are doing a lot of work here. As a real-life example, take a car factory. A car consists of many parts, assembled in some specific way, and the factory takes care of the complete process of selecting the right parts, putting them at the right place, and testing if everything went well. When you translate this to classes and objects, it is clear what the objects are here: individual cars. But what is the class in this picture? It's not the car factory, as you might think. It's the blueprint for a car; of which parts go into it. The factory comes into play when you write '$car = new Car'. This small line triggers the factory to execute the complete process of actually building a car, following the blueprint. So writing '$car = new Car' is just a small line, but one with a lot of power. Normally, you are only concerned with what an object looks like (which blueprint was used to create it), and not with how some object is constructed, or you would be writing '$sam = new Person($father, $mother)' and then had to wait for nine months before you could use the object in any way...

    Now how about subclasses? Imagine that the car factory doesn't just produce one type of car, but many of them. When you compare the blueprints of all types of cars to each other, you will probably see many of the same things over and over again. This observation can lead to a 'Car' class that defines in a more abstract way what makes a car. You can take this document and 'extend it' to make it suitable for the type of car you want. A Ferrari uses a different set of wheels than a Volvo, but it still has wheels, or it wouldn't be a car. (Note that I haven't said anything about the car factory here, as that is just the 'object instantiator', and I don't really care about that.)

    Hopefully, you'll now understand why it isn't that simple to say: okay I have this object, and now want to convert it to another one. It's like saying: "Okay, I have a Volvo, but I want to make a Ferrari out of it.". When you're programming, this problem is normally solved by doing away with one object, and acquiring a new one:
    PHP Code:
    $car = new Volvo();
    // Code involving a Volvo.
    $car = new Ferrari();
    // Code involving a Ferrari; the Volvo is gone into oblivion. 
    Vincent

  7. #7
    SitePoint Wizard samsm's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta, GA, USA
    Posts
    5,011
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Once again, I appriciate the help. I have some of your posts from the "what's so great about OOP" thread printed out so I am using those as well.

    In my mind, the difference in between turning a Volvo into a Ferrari and turning a person into a student is that you would have to (at least partially) deconstruct a Volvo before you could make it into a Ferrari. To change a person into a student all you have to do is add characteristics... nothing needs remodeling.

    However, since extending objects isn't done, I'll exaplain why I wanted to do that. Here's a scenario I just dreamed up:

    PHP Code:
    $sam = new Person;
    $sam->set_GPA('3.1');

    $StateU = new University;
    $StateU -> set_GPA_standards('3.0');

    if (
    $sam->GPA >= $StateU->GPA_standards) {
         
    $sam_as_student = new Student($sam->characteristics$new_student_characterisitics);

    Is there a way to accomplish this smoothly? Or am I constructing the whole thing incorrectly?

    Also: What happens when you want to use two extensions of one class... in other words you have:
    "student extends people" and "worker extends people"
    How would this be redesigned so that a person could be both a student and a worker?
    Using your unpaid time to add free content to SitePoint Pty Ltd's portfolio?

  8. #8
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I wouldn't use inheritance for this, precisely for the problems you already pointed out:

    What happens when you want to use two extensions of one class... in other words you have:
    "student extends people" and "worker extends people"
    In many programming exercises where inheritance is taught, it is said that a student is a person, albeit one with additional properties. This, of course, isn't strictly true. It's only true when it applies to the problem at hand.

    In this particular case, I would say that a person can have multiple jobs (or 'roles'), and that 'Student' is an example of such a role, as is 'Employee'. This would suggest an inheritance tree for roles. Something like this:

    PHP Code:
    class Role
    {
        var 
    $roleName;

        function 
    Role($roleName)
        {
            
    $this->roleName $roleName;
        }
        
        function 
    getRoleName()
        {
            return 
    $this->roleName;
        }
    }

    class 
    StudentRole extends Role
    {
        var 
    $university;

        function 
    StudentRole($university)
        {
            
    $this->Role('Student');
            
    $this->university $university;
        }

        function 
    getUniversity()
        {
            return 
    $this->university;
        }
    }

    class 
    EmployeeRole extends Role
    {
        var 
    $business;

        function 
    EmployeeRole($business)
        {
            
    $this->Role('Employee');
            
    $this->business $business;
        }
        
        function 
    getBusiness()
        {
            return 
    $this->business;
        }

    (The reason why I store the name of the role will become clear later on.)

    Of course, you could make the different Role-classes much better, for example by storing (a reference to) a real 'University'-object for a StudentRole, instead of just the name.

    Now, how would you assign roles to students? There are many, many ways to do this. You could, for example, make the Role classes a bit smarter, by storing a reference to the person that has that role in it. I choose not to do that here, because it will make finding all roles for a person very hard. The solution I select here is to store the list of roles a person has inside the Person class:

    PHP Code:
    class Person
    {
        var 
    $name;
        var 
    $roles;

        function 
    Person($name)
        {
            
    $this->name  $name;
            
    $this->roles = array();
        }
        
        function 
    getName()
        {
            return 
    $this->name;
        }
        
        function &
    getRole($roleName)
        {
            for (
    $i 0$i count($this->roles); $i++)
            {
                if (
    $this->roles[$i]->getRoleName() == $roleName)
                {
                    return 
    $this->roles[$i];
                }
            }
            return 
    false;
        }
        
        function 
    addRole(&$role)
        {
            if (
    $this->getRole($role->getRoleName()) === false)
            {
                
    array_push($this->roles, &$role);
            }
        }

    Now you hopefully see why I stored the name of the role inside the Role-class: it allows me to get that specific role from the person. Note that this implementation allows a person to have only one role of a specific type. But then this is just an example, and you can make it as complicated as you'd like.

    A note to other programmers: it's not possible to use 'foreach' to traverse the roles for some person. The roles-array stores objects and foreach doesn't handle that well: if you write 'foreach($this->roles as $role)', the variable $role will hold a copy of an array element, and not a reference to it. This is generally not what you want, especially not when the objects inside the array store references to other objects themselves. Anyway, back to the problem at hand.

    The code above allows you to write the following:

    PHP Code:
    // Create a person
    $sam = new Person('Sam');
    // Add an 'Employee' role in one go:
    $sam->addRole(new EmployeeRole('SitePoint'));
    // Add a 'Student' role:
    $studentAtPrinceton = new StudentRole('Princeton');
    $sam->addRole($studentAtPrinceton);

    // Now to get information:
    echo 'Name: '$sam->getName(), "<br>\n";
    if (
    $role = &$sam->getRole('Employee'))

    {
        echo 
    'Works at: '$role->getBusiness(), "<br>\n";
    }
    if (
    $role = &$sam->getRole('Student'))
    {
        echo 
    'Studies at: '$role->getUniversity(), "<br>\n";

    This solution has some nice properties:
    - It's simple. And 'keeping things simple' is a good programming motto.
    - It's extensible. Say you need a new Role-class. Simply write it, and all Perons in the system can immediately use it.
    - Roles can be shared. If you have many students at the same university, they could all use to the same StudentRole-object (e.g. $studentAtPrinceton), thus saving precious memory.

    In a more advanced implementation, the names of roles wouldn't be explicitly stored, and instead 'runtime type information' (RTTI) could be used, in combination with a factory class to create the Role-objects dynamically. But let's forget about that for a while; that's just me showing off

    Vincent

  9. #9
    SitePoint Wizard samsm's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta, GA, USA
    Posts
    5,011
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think I understand.

    I was formally thinking along the lines of everything being under the canopy of one class... good to see how that is not needed.

    Thanks you for the help!
    Using your unpaid time to add free content to SitePoint Pty Ltd's portfolio?

  10. #10
    SitePoint Wizard samsm's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta, GA, USA
    Posts
    5,011
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    One more thing...

    Is there a way to encapsulate the process of creating new objects in OOP?

    Here's what I mean. I have a CMS I'm making... there are classes for Articles and Catagories.

    An Article object has methods that can find out which categories it (the article) is in. At the present, the method for this queries the database and returns a list of category_IDs (which is all that is needed to create a Category object).

    -- here's where I get fuzzy on how to do things --

    I want for the Article->get_category() method to create as many Category objects as is needed. It would then store the references to the objects in an array like in Victor's last example.

    I could see this being done in a few steps but I'd ideally like to boil it down to one:
    $sample_article->get_category();
    Bam! Just like that there's an array of references to Category objects. Plus, the Category objects will be in memory for later use on a page.

    Is that doable? Should it be done or am I thinking in the wrong direction?

    Thanks for reading ,
    Sam
    Using your unpaid time to add free content to SitePoint Pty Ltd's portfolio?

  11. #11
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Again, I would think 'multiple classes'. First of all, you want a list of categories that remains in memory so that they can be used later on. You could either generate the list of all categories at the start of your program, or you could add a category to the list each time it's requested. The first option is only usable if there aren't too many categories, but it's fairly simple to implement. To make things interesting, I'll examine the second .

    Imagine a class CategoryList that stores a list of all categories. At least, to the outside it does. Internally it stores only the categories that have actually been requested before. To simplify things here, I assume that there is an instance of some Database-class called $database that supports a method query($sql). That method returns a new object that stores information on the executed query. That object supports methods like: getRowCount(), getRow($index), isSuccess(). (This is inherently better than all those other Database classes 'out there' that store a query result inside the Database class. That approach has some serious problems.)

    PHP Code:
    class Category
    {
        var 
    $id;
        var 
    $name;
        
        function 
    Category(&$database$categoryId)
        {
            
    // Setup $sql so that is selects the category with 
            // ID == $categoryId
            // ..
            
    $query $database->query($sql);
            if (
    $query->getRowCount() != 1)
            {
                
    // Ohoh, this category doesn't exist..
                
    $this->id   = -1;
                
    $this->name 'invalid';
            }
            else
            {
                
    $row $query->getRow(0);
                
    $this->id   $row['category_id'];
                
    $this->name $row['category_name'];
            }
        }
        
        function 
    getId()
        {
            return 
    $this->id;
        }
        
        function 
    getName()
        {
            return 
    $this->name;
        }
        
        function 
    isValid()
        {
            return 
    $this->id != -1;
        }
    }

    class 
    CategoryList
    {
        var 
    $database;
        var 
    $categories;
        
        function 
    CategoryList(&$database)
        {
            
    $this->database   = &$database;
            
    $this->categories = array();
        }
        
        function &
    getCategory($categoryId)
        {
            if (isset(
    $this->categories[$categoryId]))
            {
                return 
    $this->categories[$categoryId];
            }
            
    // The category is not in memory, so get it from the database:
            
    $this->categories[$id] = new Category(&$this->database$categoryId);
            return 
    $this->categories[$id];
        }
        
        function 
    getArticleCategories($articleId)
        {
            
    $result = array();
            
    // Set up $sql so that is selects all categories for the article with 
            // ID == $articleID
            // ...
            
    $query $this->database->query($sql);
            for (
    $i 0$i $query->getRowCount(); $i++)
            {
                
    $row = &$query->getRow($i);
                
    array_push($result$this->getCategory($row['category_id']));
            }
            return 
    $result;
        }

    Now, inside class Article I can select all categories for that article like this:

    PHP Code:
    class Article
    {
        var 
    $id;
        var 
    $categoryList;
        var 
    $categories;
        
        function 
    Article(&$database, &$categoryList$articleId)
        {
            
    $this->categoryList = &$categoryList;
            unset(
    $this->categories);
            
    // Like in class Category, create and run an SQL query that selects the article
            // with id $articleID, and set up this object from the result
        
    }

        function &
    getCategories()
        {
            if (isset(
    $this->categories))
            {
                return 
    $this->categories;
            }
            
    $this->categories = &$this->categoryList->getArticleCategories($this->id);
            return 
    $this->categories();
        }

    For efficiency reasons, I store the list of categories for some article inside the article, since calling getArticleCategories on the CategoryList object results in a query on the database. Now this happens exactly once.

    Now after all this, you can write code like this:

    PHP Code:
    // Select the categories from two articles. If the articles have  overlapping
    // categories, they are not requested multiple times from the database. 
    $categories1 = &$article1->getCategories();
    $categories2 = &$article2->getCategories();
    // Note, if $categories1[$i] represents the same category as $categories2[$j],
    // then they reference the same Category object, which is what we want. 
    Well that's about it, I guess. To make the code above better, you could think about the following:
    - Database access and query execution is now in all three classes. Do you really want that? And how could you get rid of it?
    - Classes Article and Category are both more or less the same kind of thing: they represent a single record in some database table. Maybe this observation can be used to write a base class 'Record'?
    - In the constructors of class Category and Article, a record is selected from the database, given some ID. If the ID was invalid, the Category (and Article) are set to impossible values, like '$this->id = -1'. This is probably not what you want: if some category doesn't exist, you don't even want to have an object for it! How could you do this? (Hint: it has to do with the first question in this list.)

    Oh, and by the way, my name isn't Victor, it's:

    Vincent

  12. #12
    SitePoint Wizard samsm's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta, GA, USA
    Posts
    5,011
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oh, and by the way, my name isn't Victor, it's: Vincent
    I'm so embarrassed! Memory error on my part, sorry. It only makes matters worse that 'Vincent' is a so much better name. Call me Steve or Saul or something, that'll even the score. Lets see... where's the red-in -the-face emoticon? Ah, this'll work:

    I'm digesting the new info... thanks! After it's covered in highlighter, arrows, circles and notes I'll probably be back for more questions. If you ever get tired of answering, suggest a good book and I'll take the hint .

    Sam
    Using your unpaid time to add free content to SitePoint Pty Ltd's portfolio?

  13. #13
    SitePoint Wizard samsm's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta, GA, USA
    Posts
    5,011
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, I've done some more reading and I'm back (had a busy couple of weeks with my other job).

    One of the things I read was "Using Objects to Create an Application" at zend:
    http://zend.com/zend/tut/tutorial-johnson2.php

    Anyway, the author stated that there are 4 categories of OO classes: Actor classes (representing people), Data classes (contain data but have limited ability to preform actions by themselves), Action classes (which perform actions) and Collection classes (which hold other objects... or references to other objects, I suppose). Is that a good reflection of good OOP style?

    Anyway my thoughts about the questions in the post above last revolve arround this theory. If I had an action class that created the object (rather than the class having a method theatr creates itself) then validation could take place before before the object was created. Plus, these action classes could be created so that queries in general parent classes. Is that close to the ideal answer?

    Also, certainly, article, category and a few other things I have planned could stem from a "Record" parent class. It makes sence... the worst thing that happens is you have to override some of the details of the parent.... in that situation you are no worse off than if they were separate classes from the start.

    Thank you for your help!
    Sam
    Using your unpaid time to add free content to SitePoint Pty Ltd's portfolio?

  14. #14
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Anyway, the author stated that there are 4 categories of OO classes .... Is that a good reflection of good OOP style?
    One good OO design rule is that you should keep your classes small. Let them do just one thing, but let them do that really well. The four categories in the article more or less force you to design your code like that, so that's probably a good thing.

    On the other hand, it requires you to design your application completely from scratch before writing any code. In the article the author first identifies all parts of the system, names them, and places them in one of the four categories. When you are working on a large application, that's easy to get wrong. And when you're halfway through the implementation of a bad design, how do you recover?

    As I said in other posts on this forum, I am a big fan of eXtreme Programming, and especially the Refactoring part. I don't design a complete application from scratch, but just a small part. Then I implement and test it. I look at the what the application must support next, prepare the existing code so that the addition is easy to make (refactoring) and add the new code. I very much like this idea, as I can change course in the middle of the implementation. I'm pretty sure that when the application is finished, it will look very different from a similar application that was completely designed up front.

    But, as always, there are some problems with XP and Refactoring. I said in a few words that "you prepare the existing code so that the addition is easy to make", but this can be a real problem. A small, trivial requirement can require you to almost completely rewrite your application! However, by reading up on the subject and by doing it a lot, this will happen less and less.

    You yourself said you were thinking about adding a Record parent class for Category and Article. Let's say we code it like this:

    PHP Code:
    class Record
    {
        var 
    $database;
        var 
    $table;
        var 
    $id;
        var 
    $rows;

        function 
    Record(&$database$table)
        {
            
    $this->database = &$database;
            
    $this->table    $table;
            
    $this->id       = -1;
            
    $this->rows     = array();
        }

        function 
    restore($id)
        {
            
    $result $this->database->query(
                
    "select * from $this->table where id = $id"
            
    );
            if (
    $result->getRowCount() == 1)
            {
                
    $this->id   $id;
                
    $this->rows $result->getRow(0);
                return 
    true;
            }
            return 
    false;
        }
    }

    class 
    Article extends Record
    {
        function 
    Article(&$database)
        {
            
    $this->Record($database'article');
        }
    }

    class 
    Category extends Record
    {
        function 
    Category(&$database)
        {
            
    $this->Record($database'category');
        }
    }

    // $database is a database connection
    $article = new Article($database);
    $article->restore(2);
    $category = new Category($database);
    if (!
    $category->restore(17))
    {
        
    // Category doesn't exist

    This works pretty good. All real database access can be done in class Record, so the classes Category and Article are pretty simple. There is a problem however, and that is that the database object must be passed on construction. Why is that?

    If you look at the four OO categories in the article, you'll see that class Record doesn't fit in any of these. You would like it to fall in the 'Data' category, but since it performs actions by itself, it doesn't. For similar reasons, it isn't an Action. It looks like an Actor, but it's clear that shouldn't be the case.

    So is the code above wrong? I don't know. I'd say it works pretty well. There's only one problem, and that is that for object instantation, we need the database object in scope. In properly layered code, that will be nasty.

    Although it may look like I made the 'mistakes' I made on purpose, I did not. In real life I also write simple classes, test them out, and then come to the conclusion that they won't work completely as intended. And that's where refactoring comes into view. Of course I'm getting better and better in it, so I don't make so many mistakes anymore.

    I could refactor class Record into one that falls in the Data category, but do I want that? You'll see that the class will become almost empty. And when a class has very few methods, and thus serves little purpose, it should be removed alltogether. So I decide not to do that, as I like the idea of having a baseclass that represents records in a table.

    "Every problem can be solved by using an indirection." This quote is one to remember, because it's true. Where does a record come from? From a table. So maybe a Table class could come in handy? Let's try:

    PHP Code:
    class Table
    {
        var 
    $database;
        var 
    $name;

        function 
    Table(&$database$name)
        {
            
    $this->$database = &$database;
            
    $this->name      $name;
        }

        function 
    restoreRecord($id)
        {
            
    $record = new Record($database$this->name);
            if (
    $record->restore($id))
            {
                return 
    $record;
            }
            return 
    false;
        }
    }

    $articles   = new Table($database'article');
    $article    $articles->restoreRecord(1);
    $categories = new Table($database'category');
    $category   $categories->restoreRecord(17); 
    Given a Table object, I can now get a record from that table without requiring the database object. Of course now I need the Table object, but that makes kind of sense. Also, when writing the application you'll find that this requirement isn't as big as the other one (having the Database object in scope).

    Anyway, we do have some new problems: class Table instantiates class Record, and not class Article or class Category. Also, the name of the table is now stored in both class Table and class Record. It makes sense to remove it from the latter one.

    I'll not go into the details of refactoring class Table so that it instantiates the right Record class, as this post is long enough without it already. I hope that I've shown that it isn't necessary to make a big, static application design before beginning to code. By doing it this way, you'll encounter the problems when they happen, and learn how to solve them in a flexible way.

    Vincent


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
  •