SitePoint Sponsor

User Tag List

Page 1 of 3 123 LastLast
Results 1 to 25 of 52
  1. #1
    SitePoint Enthusiast
    Join Date
    Oct 2001
    Location
    London
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Discussion: An approach for dealing with many classes in large PHP projects.

    _____________________________________________________________________________________________

    IS THIS A GOOD APPROACH FOR DEALING WITH MANY OBJECTS IN LARGE PHP PROJECTS?
    _____________________________________________________________________________________________

    Updated: 11th October 2001

    Notes:

    Class: A class is an abstract description of something (e.g. A computer in general)

    Object: An object is the actual instance of the class e.g. (THAT computer overthere, none other than that one).



    Having read a great deal about classes and objects on the web and various PHP books, it seems to me that object oriented programming is the way to go. It seems like an excellent way to efficiently structure your code. Each object method is responsible for accepting input and sending an output. You can change things inside your methods, and as long as the output is acceptable, then you don’t need to worry about knock on effects elsewhere in the system.

    However… the reality in PHP presents me with some problems. It seems that there are plenty of tutorials on the web for explaining how to design a single class and instantiate single objects, but inter-object communication is far more difficult and discussion avoided!

    Ideally you want to be able to instanstiate your objects once, open your database connections once, etc.

    Take the following scenario:

    PHP Code:
    $code_base "somewhere/in/the/system/";
    include_once (
    $code_base "classes/mysql_class.inc");
    $mysql = new mysql_class(); 
    The mysql_class is a database abstraction layer that handles all mysql connections and queries and reports any errors. But what happens if you have another class:

    PHP Code:
    $code_base "somewhere/in/the/system/";
    include_once (
    $code_base "classes/update_statistics_class.inc");
    $statistics = new update_statistics_class(); 
    The update statistics class is there to monitor client activity, report how many requests he/she are making, where they are making them, length of time it is taking to complete. But this class also needs access to the mysql database.

    What do we do?

    There seem to be a few approaches to this issue:


    1. Instantiate a new object inside another object

    The new statistics class has something like:

    PHP Code:
    class statistics_class {
        
        function 
    statistics_class() {
            
    $this->mysql = new mysql_class();
        }


    So a new mysql object is instantiated within the new object. But this means creating a complete new mysql object, with new open/close connections. So this consumes more memory along with the additional overhead of making the database connection. What happens when we instantiate another object e.g. test_class, and it too requires access to the database. That means another mysql object, more memory, more database overhead.

    Not happy with this.


    2. Pass the global mysql object to the new object using an alias:

    When the update_statistics class is instantiated we use:

    PHP Code:
    $statistics = new update_statistics_class($mysql); 
    Then this global mysql object is available from within the new object (passed as a reference/alias):

    PHP Code:
    class statistics_class {
        
        function 
    statistics_class(&$mysql) {
            
    $this->mysql $mysql;
        }


    On first glance, this seems like a really good idea. After all, each object has a pointer to the global $mysql object. This means that we open just one mysql connection per script and each class has time-share on the one object. We don’t need to worry about closing the connection as PHP automatically does this for you when the script ends and we never have to worry about two objects using the mysql connection simultaneously.

    So we save on having to create a copy of the mysql object and therefore memory. And we also save on database overhead as we are only opening one connection to the mysql database.

    But the downside is that when you have many objects (and you could have as many as 15 as I do), then this can also become a kludge. What happens if you end up with:

    PHP Code:
    $statistics = new update_statistics_class($mysql$object1$object2$object3 ……); 
    Then from inside the object you need to instantiate a new object, which also has to have access to the mysql object.

    PHP Code:
    class statistics_class {
        
        function 
    some_method($mysql) {
        
            
    // Invoke new object that is only required from within statistics 
            // and doesn’t need to be invoked globally.

            
    $some_other_class = new some_other_class($mysql);
        }


    It’s just messy.


    3. Create local aliases to global objects

    The last approach is one I am currently using. It still uses the idea of passing global objects around but it’s a cleaner method. You don’t pass the mysql as an alias, but allow a small script inside the class constructor to create local references to your global variables/arrays/objects.

    So:

    PHP Code:
    class statistics_class {
        
        function 
    statistics_class() {
        
            
    // Replace with contents of the create_references file. This will make
            // local aliases of all global variables including objects such as mysql
            // so we don't have to keep creating new instances.        
            
    require("classes/create_references.inc");
        }


    where the create_references.inc file is:

    PHP Code:
    <?php
    reset
    ($GLOBALS);
    while (list(
    $key$val) = each ($GLOBALS)) {
        if (
    ereg("[a-z0-9]+"$key)) {
            
            print 
    "$key => $val\n<br>\n";

            
    // Make a reference/alias from a local pointer 
            // to the global variable/array/object. Changing either one will
            // affect the value.
            
    $this->{$key} = &$GLOBALS[$key];
        }
    }
    ?>
    Since all our variables/objects are in lower case, we only extract the lower case variables from globals, and we then create a local pointer to each global variable/array/object using the line:

    PHP Code:
    $this->{$key} = &$GLOBALS[$key];

    e.gwe end up with:
    $this->mysql = &$GLOBALS[$mysql];

    inside each and every object
    Using this approach, all objects that are now instantiated will have access to all other objects which are already instantiated.

    If you were to list all the lower case aliases defined in the current object you might see:

    Code:
    argv => Array 
    argc => 1 
    code_base => /somewhere/in/the/system/ 
    working_directory => members 
    years_active => 1998 - 2001 
    debug_code => 1 
    debug => Object 
    user => Object 
    error => Object 
    mysql => Object 
    test => Object
    See how all these objects are now available as $this->error->some_method or $this->user->some_variable.

    Notice that we also have a user object. Instead of crowding out the global name space with variables that might conflict with each other, we have moved all the user variables into the user object. If for example, we want the name of the remote_user as previously defined by $GLOBALS[remote_user], we simply have to access $this->user->remote_user or $this->user->keyword for a keyword that has been selected in a form.


    IT’S ALL VERY CONVENIENT BUT

    It’s all very convenient but I get this nagging feeling (doesn’t this always happen!) Shouldn’t all objects be entities unto themselves? What happens if you call a method in the test object e.g. test_method:

    PHP Code:
    class test_class {
        
        function 
    test_class() {
        
            
    // Replace with contents of the create_references file. This will make
            // local aliases of all global variables including objects such as mysql
            // so we don't have to keep creating new instances.        
            
    require("classes/create_references.inc");
        }

        function 
    test_method() {
            
    // Requires a user variable
            
    $remote_user $this->user->remote_user;
            
            
    // Requires a connection to the mysql method
            
    $this->mysql->query(“some query that uses $remote_user”);

            or 
    alternatively:

            
    $this->mysql->query(“select from some table where user = {$this->user->remote_user});
        
            
    Then update the statistics:

            
    $this->statistics->update_statistics();

            
    Maybe update your basket too:

            
    $this->basket->add_item($item_name$quantity);
        }


    One method is now accessing the properties/methods of four other objects (a user object, a mysql object, a statistics object and a basket object). But it could just as easily be 15 objects!

    Or…. should we be using large associative arrays for user information. E.g. we may have form elements that look like:

    Code:
    <select name="select[nos_responses]">
           	<option value="100" selected>100</option>
    	<option value="500">500</option>
    </select>
    
    <input type="submit" name="Submit" value="Proceed &gt;&gt;">
    <input type="hidden" name="select[search_type]" value="Comprehensive">
    When posted, we now have the $select associative array inside PHP which consists of two keys (nos_responses, and search_type) and their values. They can be accessed as $select[nos_responses] or $select[search_type] from within PHP. The above example is known as an HTML array (and yes it does work).

    Then we can just pass this whole associative array to each class by reference:

    PHP Code:
    $test $new test_class($select);

    class 
    test_class {
        
        function 
    test_class(&$select) {
        
            
    // Replace with contents of the create_references file. This will make
            // local aliases of all global variables including objects such as mysql
            // so we don't have to keep creating new instances.        
            
    require("classes/create_references.inc");

            
    // Make the pointer available to all other methods in this object
            
    $this->select $select;
        }

        function 
    test_method() {

            --- 
    Now instead of: ---

            
    $this->mysql->query(“select from some table where user = {$this->user->remote_user});
        
            --- 
    We use: ---

            
    $this->mysql->query(“select from some table where user = {$this->select[remote_user]});
        
        }

    The above example emphasises the difference between the two approaches outlined above. First we have a local reference to the global mysql object as described previously. The difference is that the ‘select’ associative array is now passed by reference. We are no longer using a user object.


    THE BIG QUESTIONS

    What is the best way to approach inter-object-dependency?

    If we globalise all the objects and provide local pointers, are we setting ourselves up for problems in the future?

    Should we be passing variables/arrays/objects by reference to each new instantiated object?

    Are there better ways to think about inter-object communication in PHP?


    Hopefully we can stimulate some interesting debate on this topic which hasn't been covered anywhere else to my knowledge.


    Mike Mindel
    Technical Director
    Wordtracker
    (www.wordtracker.com)
    Last edited by mikemindel; Oct 15, 2001 at 05:07.

  2. #2
    SitePoint Wizard silver trophy Karl's Avatar
    Join Date
    Jul 1999
    Location
    Derbyshire, UK
    Posts
    4,411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Personally I use method 2 at the moment to pass a reference to my database handler (The PEAR:B as it happens).
    Karl Austin :: Profile :: KDA Web Services Ltd.
    Business Web Hosting :: Managed Dedicated Hosting
    Call 0800 542 9764 today and ask how we can help your business grow.

  3. #3
    SitePoint Enthusiast spoorw8er's Avatar
    Join Date
    Oct 2001
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hmmm, interesting and clear explanations of your different possible strategies to go about inter-object communication, NICE.

    Time for some comments (which are only personal opinions, so they might be totally wrong):
    (NB: in the following explanation I might not always use the pure OO name for a relation-type, but I'll try to explain by example what I mean)

    Let's start of with what is in my view an absolute no-no in OOP:

    Option 3: each object is aware of every other object existing in your app, wether it needs to deal with it or not ==> THIS IS BAD, this is not what OO is about and in most cases is a sign that your class-structure is up for a re-design.

    When figuring out which objects needs to communicate with eachother, you should look at the class-structure you designed and especially the relationships between classes. In OO style this is not considered an activity of the programming phase, but rather of the Design phase.

    In OO we distinguish three types of activities.
    The first two activities are considered the DESIGN PHASE, the last one the IMPLEMENTATION PHASE
    OOA => considering WHAT you want to do
    OOD => considering HOW you can achive that
    OOP ==> implementing your DESIGN
    Your questions and examples lead me to believe you are trying to solve a DESIGN issue during IMPLEMENTATION, which is most of the time also a BAD IDEA.
    I would therefore suggest to have another look at your design (and have a look at some different design-approaches if needed).

    Note: a class is something different than an object. A class is an abstract description of something (e.g. A computer in general) and an object is the actual something (THAT computer overthere, none other than that one). In OO-lingo: the object is an INSTANCE of the class.

    Now on to OOD and trying to solve the inter-object communication part.

    1. The HAS relationship
    Let's look at the average computer. It HAS a number of properties (e.g. CPU speed), can do (or stubbornly not do in certain cases ;^) some things (e.g. Execute programs).
    PHP Code:
    Class Computer {
      var 
    $CPUSpeed;
      function 
    ExecuteProgram ($file) {}

    A computer also HAS a number of components it uses to do certain things: e.g. a diskdrive to store data.
    In OO-lingo a component can be considered as a property of a class. In many cases these are simple variables, but in certain cases the component itself is complex enough to deserve its own class.
    PHP Code:
    Class Diskdrive {
      var 
    $StorageCapacity;
      function 
    StoreData ($file) {}
      function 
    RetrieveData ($file) {)
    }

    Class 
    Computer {
      var 
    $CPUSpeed;
      var 
    $DiskSystem;
      
    // Constructor for the class, called when an instance of the class is created
      
    function Computer {
        
    $this->DiskSystem = new DiskDrive();
      }
      function 
    ExecuteProgram ($file) {
        
    $this->DiskSystem->RetrieveData($file);
        
    // blahblahblah
      
    }

    So, when you have a HAS relationship between two classes, one should be declared as a member of the other (your strategy one)

    2. The IS relationship
    This is the famous inheritance thing.
    Again let's look at our computer, we can distinguish different types (A Mac, Wintel, IBM AS/400, HP9000, ...). Each of these is a computer and has the same basic properties and methods (e.g. Execute Program), but each of these has their own specific way of doing things and each can also add new properties and methods.
    PHP Code:
    Class Computer {  
      
    // Constructor again
      
    function Computer {}
      function 
    ExecuteProgram ($file) {
        
    // Load data and execute it
        
    .....
      }
    }

    Class 
    WINTEL extends Computer {
      
    // Constructor
      
    function WINTEL {
        
    $this->ExecuteProgram(WIN98file);
      }
    }

    Class 
    HP9000 extends Computer {
      
    // Constructor
      
    function HP9000 {
         
    $this->ExecuteProgram(Bootcode);
         
    $this->LogInUser();
         
    $this->ExecuteProgram(HPUX10);
      }
      function 
    LogInUser {}

    As you can see, it is not necessary to recode the ExecuteProgram in the two derived classes (on the condition that in both cases the same code is applicable ofcourse), we only modify or add what is needed.

    I know the example is somewhat simplistic, but I hope you catch the meaning.

    So, when one class shares the same basics with another but adds some new things, use inheritance: extend the basic class and add new properties and methods or modify the existing methods in the new class

    3. The USE relationship
    Let's take another look at our computer. In itself it is a nice thing, but unless someone actually USES it, it is also a stupid thing to have.
    Although this description might look similar to HAS, it is not the same.
    A human USES a computer, a computer is not part of a human, or vice versa (at least not yet 11/10/2001 ;^)
    Furthermore the two objects exist independently of eachother.
    PHP Code:
    Class Human {
      function 
    MakeAnnualReport(&$computertouse) {
        
    $computertouse->ExecuteProgram($program);
      }

    So, in the USE relationship normally we pass objects in by reference (your second strategy).
    (Note: some people absolutely hate this style of implmentation, but I find it is often the easiest way)

    IMPORTANT REMARK: In OO design communities there are sometimes very heated discussion about HAS and USE. Some people argue that there is no difference between the two. Indeed in the example I gave for HAS it can be argued that the computer USES the diskdrive and that the diskdrive can exist independent of the computer (maybe I should have thought of a better example ;^). Although this is true, the other way around (the computer can exist independent of the diskdrive) the statement is not true.

    In my opinion HAS is a stronger relationship than USE.
    HAS reflects an tighter dependence of one object on another, USE reflects a looser dependence.
    Or in other words
    USE-relation: the two objects exist independent of eachother
    HAS-relation: the object that HAS the other object cannot exist if it doesn't have it.

    Final remarks: although resource usage (and as a consequence performance and the likes) is a very important aspect of any system, you should always and foremost look at your class-structure and interdependencies. If you arrive at a point where every object needs to be aware of every other object, something in your design is not right (and this will lead to messy programming, and bad performance).
    A possible approach is to write a manager class. In this type of class you can instantiate all the objects you need and it will also be this class that will take care of communication between the objects.

    Simplified code example:
    PHP Code:
    Class Human {
      function 
    MakeAnnualReport(&$computertouse) {
        
    $computertouse->ExecuteProgram($program);
      }
    }

    Class 
    Computer {
      function 
    ExecuteProgram($file) {}
    }

    Class 
    Manager {
      var 
    $Slave;   // The manager HAS a slave
      
    var $Tool;    // The manager HAS some tools
      // Constructor  
      
    function Manager {
        
    $this->Slave = new Human();
        
    $this->Tool = new Computer();
      }
      function 
    GiveOrder {
        
    // Make your slave to something and tell him what to USE for it 
        
    $this->Slave->MakeAnnualReport($this->Tool);
      }

    NOTE: Some people argue the manager approach should never be used, and indeed in many cases it can (and should) be avoided. But on the other hand, when programming on Windows using MFC, this is exactly what happens. Your application starts by creating an instance of an App-class, which in its turn has some other objects and so on...

    Well, that's all I can think of for now. Hope it helped you somewhat in your quest for answers.
    Also check out OO Design methodologies.
    As always creating a good system is not just good programming but also good design. In OO this means that OOP is futile (and will bring along lots of frustation, bad perfomance, ...) if you didn't go through the dreaded OOA/OOD.
    Last edited by spoorw8er; Oct 16, 2001 at 07:28.

  4. #4
    SitePoint Enthusiast spoorw8er's Avatar
    Join Date
    Oct 2001
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Interesting link

    There is a nice article about the need for OOA(nalysis)/OOD(esign) when using OOP(rogramming) at the following location:
    http://www.gvu.gatech.edu/edtech/BOOST/designmap.html

    They use the following terms for the relations I described in my previous post:

    HAS => composition (sometimes also called aggregation)
    IS => inheritance
    USE => broadcast

    And ofcourse you can always search the web on OOA and/or OOD, lots of stuff to find.

  5. #5
    SitePoint Enthusiast
    Join Date
    Oct 2001
    Location
    London
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Class vs object

    >Note: a class is something different than an object.
    >A class is an abstract description of something (e.g. >A computer in general) and an object is the actual
    >something (THAT computer overthere, none other than
    >that one). In OO-lingo: the object is an INSTANCE of
    >the class.

    Thanx for that. I've updated the first article to reflect these differences more clearly.

    Mike

  6. #6
    SitePoint Enthusiast
    Join Date
    Oct 2001
    Location
    London
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Thanx!

    Thanx for taking the time to outline some of the OO principles for me. To be honest, you had me running to the largest bookshop in London in my quest for answers and further explanation. They had an entire bookcase (6 shelves) full of object oriented books!

    I found three to my liking and am in the process of trying to understand all the object oriented principles you've brought up and others I didn't even know about.

    One in particular is proving very useful: Object Technology (A Manager's Guide) by David A. Taylor which attempts to explain all the principles and jargon in a very clear, common sense way.

    I take your point about analysis and design. I just launched in and attempted to implement my entire procedural system using the object approach and wound up in a big conceptual mess. At least I didn't go too far with it!

    I suppose I'm also moaning about the fact that the PHP developers have implemented classes, but have not warned people of the dangers in using them; the dangers of not planning; and how to use them in large PHP projects with multiple objects.

    But let's hope this thread will clear up all these issues shortly. I'm going to post another reply when I've got my head around the concepts better.

    Mike Mindel

  7. #7
    SitePoint Enthusiast spoorw8er's Avatar
    Join Date
    Oct 2001
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Glad I could help

    Well, I'm glad to hear my post was of some help to you (although you might come to curse me for putting you on the path you are now on ;^).

    The Taylor book is a good one to start with. As you point out yourself, it tries to explain the (at times somewhat obscure) principles of OO in a language as clear and simple as possible (something which happens not nearly enough in my opinion).

    A word of warning too, as I hinted in my previous posts, there are at times heated debates on what is and what is not OO and, as for all good things, the concept of what is OO has evolved and been refined over time. Don't despair if some of the books contradict eachother once in a while.

    And another warning, sometimes the theory is very nice, but reality has its prerogatives too. Full-blown OO-style can at times be very demanding on resources and might just not work in your environment, compromises are sometimes needed. But think about them carefully (actually in my opinion a top designer knows when and how to compromise).
    There is a famous example of this: some years back a new baggage-handling system was designed (I think for Chicago Airport but not sure). The designers went all out OO. The design was beautiful, completely by the book, in short a masterpiece. Or so it seemed, because the first time the system ran it turned out that it took 48 hours to handle all the baggage of one normal working days (imaging getting of the plane and having to wait a day begore your luggage arrives, not a nice experience).

    About your remarks concerning PHP and classes, well I feel the urge for a rant coming up (and this might digress a bit from the original subject of this discussion) .....

    In my personal opinion (which can be completely wrong, but hey, at least I got one ;^) there are multiple factors at work:

    1. PHP is a nice language (I use it alot myself) but
    - it is not a PURE OO language (but then again, most of the the so-called OO-languages aren't pure), so some of the concepts of OO are not found in PHP, forcing the coders to invent some funky work-arounds. Which can be tremendous fun for the original coder, but hell for who-ever has to use his classes afterwards (or worse, modify them a bit).
    - it has not yet reached the point of stable definition (go to the Zend pages and follow the discussions for the next version, and you'll see what I mean)
    - it has many features built in, sometimes this is good, sometimes this can lead to confusion and bad code

    2. The larger part of the PHP-development community are people with a webdesign background, not people with an application-development background. I'm not saying one is inferior to the other, just that they have a different background and therefore also a different training.

    In my neck of the woods, if you are taking 'application analyst and developer' courses, 80% of your time is spent studying and doing analysis and design (considered the boring part by most students) focussing on one or two methodologies, only about 10% of your time you get to code (the fun part) learning (in my time) 6 different languages, the last 10% was real boring stuff like accounting.
    What we learned was
    - There a only a few good methods to design a system
    - A good design is important
    - The language itself is of lesser importance, make sure you choose the one that best suits your environment and/or project: for a realtime system (e.g. missile guidance), PHP might not be the best choice.
    - Our former 'lets just code it and see what happens' friends thought we were boring gits that no longer had the 'edge'.
    - People studying to become an accountant of their own free will, never had and never will have 'the edge'.

    Most webdesigners don't have that background (which is not their fault, just a fact) and were/are forced by their employers/clients to get the site up as fast as they can. After a while they grow out of HTML and venture into Java, ECMAScript, PHP, ASP and the likes (either because they feel limited by HTML or because their clients just force a technology on them, last case it the worst thing that can happen).
    But the pressure to get something up and running fast remains, so when you are faced with a deadline and two challenges (learning a new language and learning a new concept), most people tend to focus on the one that gives the quickest results, which in this case is learning the commands of the language (afterall a concept is nice, but a concept in itself does not produce much output).
    But taking that route also means that you'll encounter parts of the concepts along the way and (in most cases) you'll have to learn the hard way what these concepts are and are not ment for. And sometimes you'll think you learned something great when in fact what you learned was the absolute worst way to do something.

    Luckily a lot of webguys are very open and want to share their experiences with others and try to teach their fellow travellers something. A cynical guy would say they just want to show-off, I think in many cases (my posts included) it is a mix of the two.

    Good thing is there are lots of resources on the net, when you're stuck with a problem in PHP you have dozens of boards where you can post a question and somebody somewhere might post the answer to it.
    Sadly this need to share also means a lot of bad code is available on the net.
    And people that are faced with the pressure of getting the site out NOW don't have the time (and/or knowledge) to study and analyse it to see if it is good or bad design (of if it good design but not what they actually need in their application).

    It happens to all of us, I too have in times of deadly deadlines grabbed code from the net in an attempt to shorter development time only to find out afterwards the code is badly designed and several 'hacks' were needed and finally ending up rewriting the thing from scratch (on the whole spending more time than I would have if I started from scratch in the first place).
    But at times I have also grabbed code that was so craftily designed that I learned a few new tricks (when I found the time to study the design in detail, in most cases after the project was finished).

    So you'll find good design and bad design. Learn to live with and more important try to learn from it. When you have the time, just grab some code and study it, try to find out if it is good or bad, and why they compromised on some parts. As I said, compromise is sometimes (many times) necessary, but compromises too can be well or badly done.

    Anyway, time to stop ranting.

    Mike, I wish you all the best, both with the project and your travels into OO.
    Last edited by spoorw8er; Oct 12, 2001 at 02:46.

  8. #8
    SitePoint Enthusiast
    Join Date
    Oct 2001
    Location
    London
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Thanx

    Thanx again for your points.

    I might point out however that my days of pinching code from the net and sticking it into my programs has also come to an end. For exactly the same reasons as you pointed out.

    It was all fine in the beginning as I was finding my feet in the PHP world, but a lot of it is simply just designed badly.

    What happened to me was that I needed to get a website up quick (as you said), read many books on PHP inside out, learnt PHP over two years and am a confident procedural (with functions) PHP programmer.

    It's just that it got to a point where I had to start adapting my site with the times and as soon as I started to get a little funky with the structure, the building was threatening to topple on top of me.

    I feel it's important to point this out to people who read this thread. If you're starting out in PHP and designing a large scale PHP system for the web, then I'm you two years down the road. If I can somehow show readers that time spent learning about this new object concept, and how important it is to structure and design your code first then it's probably time well spent.

    I'm going to take a quote out of this (inspiring) Taylor book (I hope the length doesn't breach copyright) to illustrate my point:

    1. On the industrial revolution

    Just 200 years ago, there was no manufacturing as we know it today. Products were created one at a time by highly trained craftsmen who learned their trade through long apprenticeship. Individual craftsmen were each responsible for creating complete products, and they enjoyed considerable latitude in the way they plied their trade. Each product bore the unique stamp of the person who made it, and each was in a very real sense, a work of art.

    A gunsmith, for example, created a rifle completely from scratch, starting with blocks of wood and pieces of iron. Each part was carefully fabricated to fit an individual weapon. Every screw was cut from rod stock, individually threaded, and hand fitted to the pieces it would fasten together. A finished rifle might have the same general design as other rifles in its class, but each one was unique in its details and performance.

    Although it can be beautiful, individual crafting was painstakingly slow; the quality of output was inconsistent; the approach was very expensive; and it was nearly impossible to scale the process up to the level of mass production. Moreover, there was no way to standardize performance, and maintaining products in the field was often impossible because only the original craftsmen could repair their creations.

    In 1978, inventor Eli Whitney conceived a new way of building rifles that led to the modern form of manufacturing. The central concept behind Whitney’s approach was to assemble rifles out of standard parts that could be interchanged freely among the individual weapons. Specialists made each type of part, and rigorously defined standards ensured that these parts were physically identical. Other specialists assembled the parts and tested the final product.

    In this way, rifles could be produced much faster; overall quality was considerably improved; the cost of each weapon was greatly reduced; and the techniques scaled well to mass production levels. In addition, the weapons not only were more consistent in their performance but also were far easier to maintain because damaged rifles could be repaired using standard techniques and replacement parts.

    Whitney’s approach was not a refinement of existing methods but a radical departure from an accepted way of thinking – something historians call a paradigm shift. A paradigm is a view of the world that is based on assumptions so ingrained that they are rarely questioned, such as the assumption that individual gunsmiths build complete weapons. A paradigm shift requires raising those assumptions to consciousness, developing a new approach based on different assumptions, refining the approach until it works better than the old way, and making the social adjustments necessary to gain acceptance for the new approach. Paradigm shifts are rarely quick, easy, or pleasant.

    Now, 200 years after the Industrial Revolution, the craft approach to producing material goods seems hopelessly antiquated. Yet this is precisely how we create software today. Each program is a unique creation, constructed piece by piece out of the raw materials of a programming language by skilled software craftspeople. Each component is fabricated specifically for the role it will play in its particular program and can rarely be used in the construction of other programs.

    In short, conventional programming is roughly on par with manufacturing two centuries ago. Software development is painstakingly slow; the quality of software varies tremendously; the approach is very expensive; and the process does not scale well to large systems. Moreover, because each program is unique, standardization is impossible, and maintenance by anyone other than the original authors of a program is extremely difficult.

    This comparison with the Industrial Revolution reveals the transition we must make in software development. We need a paradigm shift!


    Waiting for the revolution

    To date, object technology has not yet brought about the expected paradigm shift. Twenty-five years after the invention of objects, programmers are still handcrafting new applications line by line. The only difference is that they are using objects instead of subroutines.

    To be fair to the effort, it is possible to buy reusable objects and plug them into new applications. But the objects available on the market today are mostly low-level utilities such as user interface components, database access tools, and communication interfaces. There is very little in the way of high-level business objects, and the cost of integrating these objects typically outweighs the benefits. The open, thriving market for pluggable business objects is still just a vision of the future.





    2. On Polymorphism

    Polymorphism is particularly useful when you add new kinds of objects to a system. Suppose you wanted to add mortgage-backed securities to a portfolio. Using conventional techniques, you would have to trace through your system to discover all the places where financial instruments were referenced, edit each of these to incorporate the new kind of instrument, and then rebuild, retest, and redeploy the entire system. It is no wonder that it takes so long to get simple changes made to business systems!

    In an object system, a new mortgage_backed_security class would implement its own value method. Whenever another object wanted this new instrument to value itself, the object would send it the standard value message, just as it does with any other financial instrument. So, all the objects that interact with financial instruments are totally unaffected by the change. You can add new financial instruments simply by adding new classes to represent them, without modifying your system in any other way.

    To summarize, the key business benefits of polymorphism are that it makes objects more independent of one another and allows new objects to be added with minimal changes to existing objects. These benefits, in turn, lead to simpler systems that are capable of evolving gracefully over time in response to changing needs. In short, polymorphism is an essential feature of adaptive business systems.




    Very inspiring (and sobering I might add) stuff.
    By the way, from the shelf of over 500 object books I selected another two to help me along the way:

    Object-Oriented Analysis & Design by Andrew Haigh
    The Object Primer by Scott W. Ambler

    If you know anything about them, that would be helpful. I selected them because of their intelligent writing style, and emphasis on design over lots of code.

    My final point. I get the feeling that my original question comes from being too steeped in procedural/function design. I think I have been trying to use objects like functions and that will not stand! Since I am not going to be the first to do this, I want to keep this thread alive throughout the re-design process to show how this new concept has helped (or not helped) me. If it can help others...

    Mike
    Wordtracker

  9. #9
    SitePoint Wizard silver trophy Karl's Avatar
    Join Date
    Jul 1999
    Location
    Derbyshire, UK
    Posts
    4,411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is a great thread to read guys, keep it coming. I find a lot on my Software Engineering course that most people hate the A&D side of things, myself included, I'm much more of a programmer than a person who can sit down and model a system using a standard method. Don't get me wrong, I do model the systems, but I usually model them in my own notation which I find easier and quicker to understand - BUT I am making an effort to move away from my own notation for planning project, I have just purchased SmartDraw which has templates and symbols for Project development, so I'm hoping that I'll use it and have some understandable notes.
    Karl Austin :: Profile :: KDA Web Services Ltd.
    Business Web Hosting :: Managed Dedicated Hosting
    Call 0800 542 9764 today and ask how we can help your business grow.

  10. #10
    SitePoint Enthusiast spoorw8er's Avatar
    Join Date
    Oct 2001
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Well, let's preach some more

    Welcome Karl, glad you find the thread interesting.

    WARNING
    Besides being rather long (and possibly boring), this mail will not tell you why you should OO instead of procedural style. It will however try to explain why design and a standardized way of working are so important.
    END OF WARNING

    Mike, I don't have those books myself (so many to choose from, so little money ;^), but I'm interested to hear your opinion about them after you've gone through them.

    A publisher that I found to have lots of quality books (and quality authors on the subject of OO) in its portfolio is Addison-Wesley. Some of their guru-authors tend to speak in tongues a bit and are best left until a time when you feel comfortable with the concepts and principles of OO, but some good authors are Barry Boehm, Philippe Kruchten, Grady Booch, Peter Coad, .... (some of these guys are the 'inventors' of OO).

    Karl, on the subject of notation. Yep, I understand, it does seem a drag sometimes and it is often easier to use your own style of notation. But be careful when you work with a team. If not everybody uses the same notation style (whatever it may be) and fully understands it, you'll run into trouble. Be escpecially careful with the understanding part, different styles can use similar symbols, but with a different meaning. This can lead to some interesting mistakes.
    Another funny example: remember that mars-lander thing that went wrong some time back. You know why? Well, it turned out that the team that developed function A calculated distances using inches. Function A called function B for a sub-calculation, which was developed by another team that calculated distances using the metric system. So when function B returned 1 (cm), function A happily calculated along with 1 (inch = 2.54 cm). And why did nobody notice this. Because in the design-specs they always talked about 'standard unit of measurement', but no one said anything about inch or cm.

    START THE RANT NOW

    The most important thing is you spend enough time designing and modelling before going into the coding-saloon with all guns blazing. How long enough time is depends on the size of the project/application. The bigger it is, the longer you need for design. Ofcourse you'll also need more time coding when a project is bigger, but every minute you spend on design can save hours in coding. Especially when you reach the level where you can start to reuse code from earlier projects, something rarely possible when you spend little or no time on design (of the previous projects as well as the current). This is what the first part of the quote Mike gave is about.

    Be careful with that example though. It is often cited by people trying to explain what OO is about and what it can mean for software-quality, but it is not always fully understood (not saying you didn't Mike, just trying to make it absolutely clear to everyone else).
    Personally I even think it says nothing at all about OO itself.

    Let me explain:

    At first people tend to focus on the component part of the story (Hey, these classes and objects, are those not similar to those components?). Yep, they are indeed similar. You put the components together and you get a new thing, you assemble some classes and you've got an application.
    Yep, true, but on the other hand: the craftsman also used components: he made a barrel, a trigger, a chamber, ... put it all together and ended with a working gun.

    The other part of the story is this:
    In barrel-lingo: You started out with one guy making barrels, but business is good and you take on an extra barrel guy. Well, tell him the exact same parameters, teach him to work exactly the same way, and then ask for a hundred barrels a day.

    This second part is the real revolution (but not always so obvious, or maybe too obvious): suddenly everybody doing the same thing had to work using the same methods and principles to garantuee the result would be the same. This is the aspect that, in my opinion, leads to quality (it also leads to frustation and boredom for the many factory workers, remember Charlie Chaplin in Modern Times)

    Important Note on Testing:
    The goal of testing changed significantly:
    - The craftsmen didn't test if every barrel was identical to every other barrel they made. After all parts were made they tested if they fitted together and if the end-product worked. If it didn't they remade some (or all parts).
    - In a factory-environment you first make a design, then a protoype and test if the prototype works as expected. If it doesn't you redesign some parts (or all), make a new protoype and retest. If the prototype test is succesfull you go into production mode and you only need to test if every component produced is according to design-specifications to make sure they fit together. It is the design (and prototype testing) that garantuees the end-product will work.

    Another nice aspect of this approach is the following:
    You start out producing .45 guns, but suddenly .38 are very popular.
    Well no problem, just make a new design, build a prototype and test it. If it works, tell the barrel guy and the chamber guy (and the testers ofcourse) the new dimensions and problem solved. Why?
    Because the barrel guy is still making barrels using the same techniques, only a different tool (a smaller dril-bit).

    Important Note on Quality:
    Remark that using a different production technique not necessarily leads to inferior or superior quality. It might, but is not garantueed.
    Important here is the defintion of quality.
    - According to ISO quality is repeating a certain process and arriving at the same result as before.
    This does not mean the result itself is good, it just means you are consistent in what you do. You have the process under control.

    Ofcourse your customers might disagree with you. If you consistently produce guns that fall apart after being used once, they might start shopping around for another manufacturer.
    But this aspect is actually VALUE, not QUALITY.
    Look at it from this point of view:
    Say you make a gun that can only be used once but it only costs the customer 1 Euro.
    Your competitor makes a gun that can be used 100 times before breaking up, but it costs 50 Euro (reason: he uses another production technique which leads to better guns, but also is very expensive to execute).
    (Note that the price per usage for the seond guntype is lower).
    The average customer only uses a gun three times.
    What would you buy, being the average customer?
    Well, I would buy three of the first type, spending only 3 Euro in total instead of the second type, risking to waste 47 Euro (yep, I'm a tight ******* when it comes to money ;^).

    How good a gun should be (how long it should last for instance) and how much customers would be willing to spend for that are two important design-requirements. These will (among other things) help you to decide wether you use the expensive production technique or the cheap one.

    This is why DESIGN is so important, it should make sure you will be producing the right sort of gun at the right price.

    Ofcourse customer wishes might change. If for instance after five years, people suddenly start using their guns more (say 40 times), you should start thinking about a new design and possibly also a new production technique. This is why you regularly check wether the original requirements are still valid. In this case you would even want to keep track of how the usage trend of guns evolves over time to have a new design (and production method) ready to roll before customers start switching to the other manufacturer (if not you might loose valuable time while you competitor is raking in big money with a big smile on his face).

    IF YOU ARE ONLY INTERESTED IN THE CONCLUSION, START HERE

    So what does all this mean for software-development:
    Well, actually (personal opinion again) software-development should be called software-production, after all that is what we do.

    - Software developers (designers, programmers, testers, ....) should adopt a standard way of working with each worker having a specific responsability (and sadly enough this might mean it becomes a boring job, just like for the factory workers).

    - We should change our view on testing, the most important test (the will the complete thing work test) should be done quite early in the development cycle, at the end of the design phase at the latest. Afterwards testing is ofcourse still needed, but only to see if the software components produced are inline with the specifications.

    - (ISO-)Quality: it doesn't actually matter if you use procedural or OO style (just make sure the whole team uses the same style), both can lead to quality (because you use a standard way of working) if you are able to repeat how you do things. If you can't produce quality using procedural, you won't produce quality using OO.

    - Value: one method may indeed lead to better results than the other, but this depends on how much the customer is willing to spend on it, how familiar you are with that method and how much it might cost you to use that method.

    - Regularly check what is happening on the market and to your applications, try to be ready with a new product before the old one is useless. If needed, make sure you start learning new methods, languages, whatever before you will actually need them.

    Little example on these last two points:

    A client comes to you and has a big budget for a big project.
    Your company is absolutely brilliant (and very used to) procedural style, some have heared about OO (in the pub around the corner, last night) but that is all.
    Seeing the size of the project (and having heard about all the merits of OO on that wild party last week) you feel tempted to try it in OO.

    I would advise very much against it. As Mike himself already experienced, switching from procedural to OO is not so straightforward. You have to adjust the way you (and your designers, coders, testers) think about problems, you (and your coders) have new languages (or new options) to learn, you (and your coders and testers) might need new tools (finally buy that C++ compiler and get rid of MS Quick C V1.0), .... this will cost a lot.
    Not too mention the risk you are taking with the project itself, this is like thinking you can fly when you now how to fall (well both happen in the air don't they ;^).

    Now if half of your team was already prepared on OO by doing smaller projects with that style before, then you have a chance to pull it of.

    Well, that's all for today

    All comments and/or different opinions are welcome
    (as long as you present a good argument, don't just say 'IT SUCKS')
    Last edited by spoorw8er; Oct 12, 2001 at 10:28.

  11. #11
    SitePoint Enthusiast
    Join Date
    Oct 2001
    Location
    London
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Key principles I have learned from the Object Techology book

    Thanx again for your comments.

    I agree with pretty much everything you said there. And you've explained it well. However I want to take the assumption that a user reading this thread has taken the plunge into object oriented thinking with PHP....

    12th October 2001 after reading Object Technology by David A. Taylor.

    Ok. I've finished reading this book (about 174 pages - takes about two days) and digested the material.

    It's an excellent primer and really helped to clarify many of the object concepts that had me stumped before. So I recommend it to anyone who is stuck in the same position as me.

    The main thing it did was helped jolt me out of the narrow-mindedness of the procedural approach and open me up to how flexible the object oriented approach actually is.

    Here are the key things to consider. I’m bringing the focus of this thread back to the discussion at hand – which is how to think about inter object communication in PHP.

    Again I'm going to quote a few paragraphs as this guy just explains things so well!


    1. Objects should be encapsulated.

    "The way objects interact with one another is to send messages asking objects to carry out their methods. A message is simply the name of an object followed by the name of a method the object knows how to execute. If a method requires any additional information in order to know precisely what to do, the message includes that information as a collection of data elements called parameters. The object that initiates a message is called the sender of that message, and the object that receives the message is called the receiver."

    "An important function of classes is to specify the messages that objects of this kind will make available to other objects. The set of messages an object commits to respond to is called its message interface. This interface is specified as a collection of message signatures, each of which defines the name and parameters for a particular message. The only design requirement placed on a class is that it provide a method to implement each message specified in its interface. The internals of the class are completely hidden behind this interface and may include any number of variables as well as ‘invisible’ methods that are used only by the object itself. (A good convention in PHP is to put a _ before any hidden variables or methods as PHP that does not provide a facility to automatically hide them in a class)."

    "Packaging related data and procedures together is called encapsulation. The key to object encapsulation is the message interface. This interface (like the membrane) surrounds the object (cell) and acts as the point of contact for all incoming messages. It also acts as a barrier between the internal structure of the object and everything that lies outside the object. Like a cell’s membrane, the message interface ensures that all interactions with the object take place through a pre-defined system of messages that the object is guaranteed to understand and handle correctly."

    "Just as cells don’t ‘read’ each others’ protein molecules, objects don’t touch each others’ data structures. Rather, objects send each other messages that call methods into action. These methods, in turn, access the required variables."

    (David A. Taylor, Object Technology - A Manager's Guide).

    So. In a nutshell. Make most of your variables/methods private to your object. Only allow the object to talk to other objects through this message interface.

    Question:

    Now I’m not entirely sure whether he means that you can have multiple message interfaces, or whether it is good practice to have just one. Normally in PHP, a class will expose several methods when it is written. E.g. say we have a mysql abstraction layer we might have:

    PHP Code:
    class mysql_class {

        function 
    mysql_class($mysql_host "localhost"$mysql_username "root",
            
    $mysql_password "etybetyb"$mysql_port "3306") {
        
            
    // Define standard variables
            
    $this->mysql_host $mysql_host;
            
    $this->mysql_username mysql_username;
            
    $this->mysql_password $mysql_password;
            
    $this->mysql_port $mysql_port;
        }            
                
        
        function 
    connect_host() {
            
    Perform the connection to the host…    }


        function 
    connect_database($mysql_database "User") {
            
    Perform the connection to the database…
        
    }

        function 
    query($sql) {
            
    // Take the users query and execute it
            // Return the results    
        
    }
        

        function 
    display_error($error_message$error_number) {
            
    // Report an error and quit the script
        
    }


    We would first instantiate the class, then we connect to the host, then the database and then perform the query. So something like:

    PHP Code:
    $mysql = new mysql class();
    $mysql->connect_host(localhost);
    $mysql->connect_database(database_name);
    $mysql->query("some sql statement"); 
    So there are quite a few ‘message interfaces’ here. But if we were to use just one then perhaps we could change the query function to:

    PHP Code:
    function query($sql) {
        
    // Take the users query and execute it
        // Return the results    

        // Make sure we have an open connection first
            
    if($this->mysql_status == false) {
                
    $this->connect_host();
                
    $this->connect_database();
            
    $this->mysql_status true;          
        }

    Then we simply access the mysql object as:

    PHP Code:
    $mysql = new mysql class();
    $mysql->query("some sql statement"); 
    The query function is the 'single message interface' and it is responsible for making the connection to the host and to the database if the mysql_status variable is set to false. The advantage here is that we don’t have to worry about the ‘connection’. If a connection does not exist, then the object goes and makes one. If it does exist, then great!

    What happens if we have another method for getting the table list:

    PHP Code:
    function get_table_list() {
        
    $this->result = @mysql_list_tables($this->mysql_database$this->mysql_connect_host
        or 
    $this->display_error("Unable to find any tables in the database on server: 
        
    {$this->mysql_host}"mysql_errno());

        for (
    $i=0$i mysql_num_rows($this->result); $i++) {
            
    $this->table_names[] = mysql_tablename($this->result$i);
        }
        
        return 
    $this->table_names;

    This method is another message interface. It is accessed with something like

    PHP Code:
    $table_names $mysql->get_table_list(); 
    Presumably however we could place this functionality into one single message interface – the query method. Perhaps we should make sql statements:

    PHP Code:
    $mysql->query("sql""some sql statement"); 
    and a call to the get table list as:

    PHP Code:
    $mysql->query("info""get_table_list()"); 
    The single message interface 'query' could then take the responsibility of processing your request and make whatever internal calls to its methods, finally passing back the result to the caller.

    PHP Code:
    function query($request$parameter) {
        
        
    // Take the users query and execute it
        // Return the results    

        // Make sure we have an open connection first
        
    if($this->mysql_status == false) {
            
    $this->connect_host();
            
    $this->connect_database();
            
    $this->mysql_status true;         
        }

        if (
    $request == "sql") {
            
    Perform the sql query statement
        
    elseif ($request == "info") {
            
    Call the method requested
        
    }
        
        Return 
    whatever result we get;

    This way the mysql object is truly encapsulated behind a single message interface. What do you reckon?


    2. Think in terms of multi-levels

    "Here is a case in point. The cell is only the most basic level of modularisation in complex organisms. The next higher level is that of the organs, such as the heart and lungs. These organs, in turn, are ‘organized’ into systems, such as the circulatory and respiratory systems. Finally, these systems combine to form the organism itself. What is fascinating about these levels of modularity is that the functioning of each level is independent of the ones below it. Replace the heart with a mechanical pump and the circulatory system continues to work quite nicely, despite the fact that the pump has a very different design and is made of radically different materials.

    What is particularly striking to me is how few layers are required to account for the wondrous variety and complexity of living systems. We can surely benefit from looking at the incredible results of this elegant system of multilevel modularity. If we can keep the layers independent of one another, we can build extremely sophisticated, flexible business systems with no more than three or four layers.

    We already have the mechanism for creating these layers – the composite object. What we need to do is use this mechanism in a way that mimics the architecture of living systems. Instead of building haphazard composite objects that vary in depth and complexity, we should strive to define distinct layers of composition. Each of these layers should be a complete, understandable design in its own right, independent of both the structure of the lower levels and its uses in higher levels."

    "Objects should be used to encapsulate other objects on multiple levels with no more than nine objects at each level. The goal here is to make large-scale designs as simple and well structured as possible. Research has shown that the span of mental apprehension is about five to nine discrete items. A ‘flat’ design consisting of 729 objects- not a particularly large number in software designs – is nearly impossible for people to grasp. In this design, there are more than half a million potential connections to consider! However, the same design structured in three levels of nested nines can be understood without considering more than 81 potential connections – and usually far fewer – at any one time."
    (David A. Taylor, Object Technology - A Manager's Guide).


    Question:

    This was a fascinating insight. In practical terms, I believe this is suggesting that we should define our lowest-level objects first. E.g. a mysql abstraction object, a template display object, a parsing object, a socket object. All these objects do not require interaction with other objects in order to do their duties. If I ask the socket object (through its message interface(s)) to go and get me a web page, the socket will do whatever it needs to do and either pass me back the web page, or it won’t. The same with the mysql object. It makes the connection, queries the database and passes back the info or it doesn’t.

    Then on the next level I will have a composite object e.g. a caching class. This is responsible for accepting an input and checking to see whether it is in the database or not and returning either the cached page or not. It also might accept a page for storage.

    PHP Code:
    class cache_class {

        function 
    cache_class {&$mysql} {
            
    $this->mysql $mysql;
        }    

        function 
    retrieve_page($url) {
            
    // Check if it’s there. If yes then return 
            // it, otherwise return false
        
    }

        function 
    store_page ($url) {
            
    // Store page in database using mysql object
        
    }


    Notice that we have passed the mysql object by reference here. A copy is not made, but we have made a reference to it. So the cache_class is a second level composite object that has ties with one other object – the mysql object.

    Finally, we hit the third level (which consist of both first level objects and one second level object). E.g. say we want to retrieve a web page but want to check whether it has been cached in the database first. If not, retrieve it, then cache it. So:

    PHP Code:
    class retrieve_web_page_class {

        function 
    retrieve_web_page_class {&$mysql} {
            
    $this->mysql $mysql;
            
    $this->socket = new socket class();
            
    $this->cache = new cache class(&$mysql);
        }    

        function 
    get_page($url) {

            
    // Ask the cache if the page is there
            
    $web_page $this->cache->retrieve_page($url);
            
    // If it is then return it
            
    if ($web_page) {
                return 
    $web_page;

            
    // If it isn’t, then go and get it
            
    } else {
                
    $web_page $this->socket->retrieve_page($url);
                
    // If page exists then store it in the cache
                
    if ($web_page) {
                    
    $this->cache->store_page($url);
                    return 
    $web_page;                
                } else {
                    return 
    false;
                }
            }
        }

    Leaving aside any debate about whether we should have a single message interface for cache e.g. $this->cache->interface("retrieve page", $url) and $this->cache->interface("store page", $url); we can see how just a few lines of code have created something that might have taken hundreds of lines in ordinary procedural code.

    Useful stuff, this concept of levels. But I would still argue that all this passing around of the mysql object as a reference is a major pain. Could we not just instantiate it globally and automatically create a local reference to it in each constructor (as per method three in the article at the top of this thread)? I don’t know. Still thinking about it.

    Finally, I’d like to point out that the Taylor book goes to much greater lengths in describing object technology and its implications in adapative business environments but I want to focus all attention on the problem at hand.

    Mike Mindel
    Wordtracker
    Last edited by mikemindel; Oct 15, 2001 at 05:22.

  12. #12
    SitePoint Enthusiast spoorw8er's Avatar
    Join Date
    Oct 2001
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi again Mike,

    Yep, you're right. Let's stick to the original object of the discussion: object orientation, after a small rant (I promise only a small one and it ties in to some of the subjects you mentioned).

    RANT ALERT
    From my previous post, people might get the idea I have no preference in which method (procedural or OO) to use.
    Actually I do prefer OO-style, because due to the underlying principles like inheritance, encapsulation, polymorphism, programming against an interface (some called programming by contract) it forces you more to think in terms of singular functional components (or molecules if you will) than the average procedural language does, thereby making it somewhat easier to achieve the software factory.
    Like I said the concept of classes and objects is very similar to that of components or molecules (I really like that last analogy, better than the component one).
    END OF RANT

    OK, back to your questions now (And boy, you are a fast reader, don't you have anything else to do? Like write some good code ;^)

    1. Encapsulation
    Well, the point of a class is to hide/protect the internals from and only expose a number of interfaces to the outside world.
    This means we have a concept of private (hidden/protected) and public (accessible) parts of a class.

    Sidenote: this is one part where PHP is not PURE. There is currently no concept like PRIVATE in PHP (V4.0.6). All class-members and methods are considered public. There is some talk to introduce PRIVATE in V5, but the vote is still out on that.

    Regarding datamembers:
    'PURE' OO is that all datamembers of a class are PRIVATE. If the content of a datameber must be accessed from outside the class (for reading and/or writing) it must be done thru one or more methods.
    In some environments people call datamembers 'properties' and the methods used to acces 'property methods'. These property methods are ofcourse public (that's the whole point of them) and give you, the class designer/developer, a way of controling what people do with that data. In a write method (a 'set_property') you can check if the data received is within acceptable limits etc ... before stoing it in the private member.
    If you don't want a the content of an internal datamember publicly changeable or readable, don't write a write or read method (a 'get_property') for that member. Or write a get_property method that only passes the content out on certain conditions, whatever.

    In short this gives you a lot of power on how people can use your class and helps you to ensure they use it correctly.
    (Sidenote for PHP: like I said PHP doesn't have the concept of private, so there is nothing to stop some other coder filling your datamember with utter rubbish.)

    This explanation should also make it clear there is no obligation to stick to just one interface for the whole class.

    Regarding methods:
    They can be private (no one outside the class has access) or public (every one outside the class has access). There is also a concept called near (or friend), where you say which outsider can use the method, but this is rarely used (and I feel it is somewhat against the principles of OO).

    PRIVATE methods can only be accessed from inside the class and are mostly used in a manner similar to functions in procedural language. If you find yourself writing the same five lines of code over and over in the different methods of your class, those lines are good candidates to put in a private method.

    PUBLIC methods (sometimes called interfaces) are the way to operate your class from the outside. Normally you have one PUBLIC method per functionality you want to expose.

    Some languages (e.g. JAVA) are very strict and force you to write at least two definitions for a class, one where all members and methods are private, and a second one (the INTERFACE) containing the PUBLIC methods (and these do nothing more than calling the private methods).
    This definition of INTERFACE is potentially more powerful than the one where an interface equals a public method (Note Taylor talks about the interface equals public method definition).
    Here you can have one class-definition containing the datamembers and private methods and several INTERFACE descriptions, each containing a different number of PUBLIC methods.
    What is more powerful about that?
    Well, you could write an INTERFACE exposing certain properties and methods that are available at runtime and another interface exposing properties and methods that are only available in your development environment.
    As an example of the use: the average Windows control (e.g. a checkbox) works like this. At runtime you can select or deselect the checkbox which is actually setting a runtime property.
    At design time, in your Visual Basic (vade retro Satanas), you set other properties like for instance the position of the checkbox in the form.

    But, as said, PHP does not support the PRIVATE concept. However when coding try to stick to these principles, they do make life easier.

    A last important aspect of programming against interfaces is that you, the class-developer, are forbidden (morally that is) to change an interface once you have released your class to other developers.
    You may change the internal working of a public method, but the number and type of variables passed in and out (sometimes called the signature) should remain the same.
    If you wouldn't stick to this agreement, this would mean that every application that uses your class would run the risk of breakdown when the new version of your class is installed.
    If you need to change the signature of a public method (and sometimes this is unavoidable if you want to expose new functionality) the only thing you can do is write a new public method and keep the old one as is. This way an application developed against version one of your class still works with version two. An application developed against version two can ofcourse directly use the new interface.

    An example:
    PHP Code:
    version one of the class:

    class 
    my_class {
      var 
    $private_one$private_two;

      
    // some really nice pubblic method
      
    function public_one ($input1$input2) {
         
    // this does some really nice stuff
         
    $this->private_one $input1;
         
    $this->private_two $input2;
         return 
    TRUE;
      }
    }

    version two of the class:

    class 
    my_class {
      var 
    $sum_one_two;

      
    // some really nice public method
      
    function public_one ($input1$input2) {
         
    // this does some really nice stuff
         
    return $this->public_two($input1$input2);
      }
      
    // a more powerful way
      
    function public_two ($input1$input2) {
         
    // this does some really nice stuff
         
    $this->sum_one_two $input1 $input2;
         return 
    TRUE;
      }

    So it is not only possible to have several interfaces for a class, it is a good thing to be able to do that
    (it is just sad that PHP doesn't allow you to encapsulate (hide) the private methods and members).

    In your example I wouldn't try to over-encapsulate your class. What I would consider however is grouping certain steps behind one function. For example, if your idea when designing the class is that whenever someone connects to a host, he should also directly after that connect to a database, write only one method that executes the two steps. The developer using your class will be grateful: he only has to type one line instead of two.

    Furthermore, if you don't want to allow the class-user to decide which host and database he connects to, setup the connection directly in the constructor (and use mysql_pconnect instead of mysql_connect, the first one uses pooled connections and is less of a strain on resources), then he only has to type:

    $mydatabaseobject = new Mikes_database_class();

    Multi-levels
    Yep, this is powerful stuff. And this has directly to do with the different type of relations I mentioned in my first post. So this is a DESIGN issue (woohoo).

    It suggests your top-level classes should be built using lower-level classess. Remember a computer HAS a diskdrive, HAS a CPU, HAS a motherboard and so on ...

    However, when going thru the typical OO-design process you don't start finding those lowest level classes first, you don't even try to find them first (although some are sometimes so obvious you can't miss them).
    You should look at the big picture first and try to dissect that. To keep with the organ example: when you look at a human you don't say 'WOW, what a nice bunch of organs (or even molecules)'. It is only after looking closer you see the different components (the nerve system, the digestive system, ....). And when looking closer at one component you discover that one in itself can be further dissected (a heart, arteries, blood, ....).
    This is an exercise very similar to decomposition in procedural style.

    Doesn't mean it is all top-down stuff however. Sometimes you arrive at a point that makes you go up again and have another look at the previous level (or even the one above that one).
    In OO style it is quite normal to iterate several times.

    For instance: in your quest you start of recognizing pages and users as important elements.
    You design the page-class which includes a method where you do a query to retrieve it from a database. You are content with this part of your design (this means you feel that at this point you have no more to add to it) and now turn to user. Again you design the class and suddenly you arrive again at a method where you do a query to retrieve information from a database.
    Hey, I've done this type of thing before, you think.
    Yep, you did it for the page. When you start to think about it a bit further you realise that the important similarity is that you do a query to retrieve information (even although the information itself may be different and stored in different tables), so you decide to design a class that does just that: store 'A piece of information' in 'A table', which 'piece of information' and 'table' will be passed in variables when calling the method.
    After you have done that, you have another look at the page and user classes and change their design so that instead of doing the query directly in the page-class and user-class methods, you instead call the new database class, passing in the information and tablename thru the method-call.

    Simplified code to illustrate
    PHP Code:
    After first iteration you have this

    class page {
      
    // a lot of other stuff
      
    ...
      
    // store a page
      
    function store_page () {
         
    INSERT page_info INTO table_pages;
      }
    }

    class 
    user {
      
    // a lot of other stuff
      
    ...
      
    // store a user
      
    function store_user () {
         
    INSERT user_info INTO table_users;
      }
    }

    After the second iteration:

    class 
    database {

      
    functtion store_it (infotablename) {
        
    INSERT info INTO tablename;
      }
    }

    class 
    page {
      
    // a lot of other stuff
      
    ...
      
    // store a page
      
    function store_page () {
         
    database->store_it(page_info,table_pages);
      }
    }

    class 
    user {
      
    // a lot of other stuff
      
    ...
      
    // store a user
      
    function store_user () {
         
    database->store_it(user_infotable_users);
      }

    - When designing classes you start with looking at the top-level, trying to identify real-life things
    - You take one of those real-life things and start to analyse what it is, what it knows and what it can do.
    - At a certain point you'll feel you have at the moment nothing more to add to your design for that thing
    - So you take the second top-level real thing and start analysing it
    - And maybe a third even and a fourth until
    - You suddenly come up against a similarity, you recognize a certain functionality as being similar (and not identical) to some other functionality you found in another class.
    - Analyse the functionalities, try to abstract these similarities to a level where you can say they are identical things
    - Take that abstraction and make a class of it.
    - Revisit you previous designs and adapt them so that they make use of the new class
    - Continue with analysing the other things

    The important lesson here is that you should not try to identify all classes at your first go and that you certainly should not start with looking at the lowest level.

    Regarding your reference dilemma:
    Passing objects around by reference does seem a lot of work sometimes, an alternative (a style which is used a lot by the way) for this type of general, used allover the place things is not to make a class for them but just stick to standard procedural way for those ==> code some general functions and call those from within your different classes.
    Like I said in my previous post, in an ideal world (with an ideal OO-language) you want the whole thing to be pure OO, but fact is that sometimes you have to make some compromises. This can be one of them. Important thing is that you can explain with rational arguments (e.g. testing of the two alternative appproaches has shown that approach A is more performant) why the compromise in that particular situation would be better than pure OO.
    A compromise is ofcourse always a trade-off, think carefully what you are trading against what (for instance performance versus code-maintainability, resource-usage versus performance, ....).

    Hope this helps......
    Last edited by spoorw8er; Oct 13, 2001 at 06:11.

  13. #13
    Happy Holidays !! Paul S's Avatar
    Join Date
    Mar 2001
    Location
    Mexico
    Posts
    1,287
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Wow spoorw8er, this is a great thread to follow. It helped me to clear some OOP concepts.
    I'm used to program on C++ and as you can guess I've found some restrictions writing OOP applications with PHP.
    I just want to congratulate you for those excellence references you have given

    Thanks
    Paul S

  14. #14
    SitePoint Enthusiast spoorw8er's Avatar
    Join Date
    Oct 2001
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by Paul S
    Wow spoorw8er, this is a great thread to follow. It helped me to clear some OOP concepts.
    I'm used to program on C++ and as you can guess I've found some restrictions writing OOP applications with PHP.
    I just want to congratulate you for those excellence references you have given

    Thanks
    Paul S
    Thanx, but Mike should get the credit.
    - He's the one that started the thread
    - He explains in a clear way how he interpretes the concepts of OO and the problems he sometimes runs into when translating theory into practice
    - He is not afraid to ask for other views on the subject

    All I'm doing is trying to explain how I try to tackle some of these problems

  15. #15
    Happy Holidays !! Paul S's Avatar
    Join Date
    Mar 2001
    Location
    Mexico
    Posts
    1,287
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yea, you're right. Congrats Mike (also thanks for the book reference)

  16. #16
    SitePoint Enthusiast
    Join Date
    Oct 2001
    Location
    London
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    A couple of additions

    Thanx guys. Just saw a gap in general understanding (including my own) and wanted to address it publicly.

    Spoorw8er,

    1. On encapsulation

    That was another good post. I agree with you that exposing a few methods (message interfaces) is probably the way to go, rather than exposing just one. But also try to group as much functionality as you can behind each one.

    I think that for PHP purposes, we should perhaps just add a _ in front of private methods and properties to prevent them from getting confused with public ones. It's the best we can do until the Zend 2.0 engine possibly incorporates private member variables (PHP5?).

    2. Regarding the description of Objects as molecules/atoms/cells etc. Let's bring out the description that Taylor uses to clarify this matter:

    "Nature's Building Blocks

    The basic building block out of which all living things are composed is the cell. Cells are organic 'packages' that, like objects, combined related information and behaviour. Most of the information is contained in protein molecules within the nucleus of the cell. The behaviour, which may range from energy conversion to movement, is carried out by structures outside the nucleus.

    Cells are surrounded by a membrane that permits only certain kinds of chemical exchanges with other cells. This membrane protects the internal workings of the cell from outside intrusion, and it also hides the complexity of the cell and presents a relatively simple interface to the rest of the organism. All interactions between cells take place through chemical messages recognized by the cell membrane and passed through to the inside of the cell.

    This message-based communication greatly simplifies the way cells function. The cells don’t have to read each others' protein molecules or control each others' structures to get what they need from each other. All they do is send the appropriate chemical message, and the receiving cells respond accordingly.

    The cell is truly a universal building block. All cells share a common structure and operate accordingly to the same basic principles. Within this generic structure, however, infinite variability is possible. For example, plant cells have a hard outer wall to make them rigid; blood cells are mobile and specialized to transport gases; and muscle cells are able to distort their shape to perform mechanical work. But this tremendous variability is not chaotic; it’s all neatly organized – or 'classified' – in a hierarchy of specialized types and sub-types.

    Packaging related data and procedures together is called encapsulation. The key to object encapsulation is the message interface. This interface (like the membrane) surrounds the object (cell) and acts as the point of contact for all incoming messages. It also acts as a barrier between the internal structure of the object and everything that lies outside the object. Like a cell's membrane, the message interface ensures that all interactions with the object take place through a pre-defined system of messages that the object is guaranteed to understand and handle correctly.

    Just as cells don’t 'read' each others' protein molecules, objects don’t touch each others’ data structures. Rather, objects send each other messages that call methods into action. These methods, in turn, access the required variables."

    (Chapter 2: Objects: Natural Building Blocks - Object Technology - A Manager's Guide, David A. Taylor)


    3. On multi-levels

    Again, I like the way you show that object creation is a fluid process. You try and name as many as you can at the beginning, but this is open to change as you start coding. I'd also like to reiterate to people reading this thread that:

    'Objects in your system should usually represent real-world things. Talk about cash registers and vending machines and stop lights, not linked-lists, hashtables or binary trees.'

    (Taken from a URL you gave in a previous post)
    http://www.gvu.gatech.edu/edtech/BOOST/designmap.html

    This was definitely a mistake I was making. In fact, I would go as far to say that you should try and make your object choices as generic as possible. Don't create a MySql object, create a "database" object where you use MySql. But if you later change it to Oracle then all you have to do is change the class functions, you don't have to worry about renaming all the function calls in your site from MySql to Oracle.
    Last edited by mikemindel; Oct 15, 2001 at 05:57.

  17. #17
    SitePoint Enthusiast spoorw8er's Avatar
    Join Date
    Oct 2001
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Re: A couple of additions

    First of all, I like this thread very much.
    Reading your remarks and trying to explain my views in a clear way forces me to think about some of the approaches I have come to take for granted over the years. And inevitably I find some gaps between what is and what should be, so we're all getting something out if it.

    Originally posted by mikemindel

    1. On encapsulation

    I think that for PHP purposes, we should perhaps just add a _ in front of private methods and properties to prevent them from getting confused with public ones. It's the best we can do until the Zend 2.0 engine possibly incorporates private member variables (PHP5?).
    The _ style notation to indicate that a member or method should be viewed as private seems like a good compromise at this time (until the real private comes in hopefully PHP5). It is proposed and used by the guys working on the PEAR library and seems to have become somewhat of a de-facto standard.

    Originally posted by mikemindel

    2. Regarding the description of Objects as molecules/atoms/cells etc.

    "Cells are organic 'packages' that, like objects, combined related information and behaviour. Most of the information is contained in protein molecules within the nucleus of the cell. The behaviour, which may range from energy conversion to movement, is carried out by structures outside the nucleus."
    This is why I like the cell image more than the component image. An object combines information and behaviour, just like a cell, and has the responsibility for implementing that behaviour. It is the cell itself that does the energy conversion, not some outside element, that element only provides the trigger by sending certain messages.

    The whole responsibility-stuff was one of the areas I found very hard to grasp when I started with OO (and remains the area I am most likely to make mistakes in during design).

    Originally posted by mikemindel

    3. On multi-levels

    Again, I like the way you show that object creation is a fluid process. You try and name as many as you can at the beginning, but this is open to change as you start coding.
    I feel there are two types of changes in OO style
    1. Changes to the way objects communicate with eachother (who has contact with who, what messages are passed, what methods are exposed by each object)
    2. How an object processes a message internally (the internal process-flow of a method).

    Type one changes are very difficult to do during coding without risking instability, for the same reasons as when you would use procedural style: you are hacking the design.
    When you find yourself doing several changes of this type, this is a sign that your design was not yet fully mature. Better lay the coding aside for a while and have another look at your class-structure and design, trying to find out where the root cause of your need for change lies.

    Type two is another matter, these are (in most cases) purely implementation issues (e.g. do I use a linked list or an associative array, do count the rows in the table first and then loop-fetch or just fetch until end of table), things that are not ment to be solved during design phase (although design might provide indications on the best approach) and that will be subject to some tuning and bugtesting and the likes....
    Be careful though, always keep your eyes open that you do not accidently stumble from a performance fix into a design-hack.

    In fact, I would go as far to say that you should try and make your object choices as generic as possible. Don't create a MySql object, create a "database" object where you use MySql. But if you later change it to Oracle then all you have to do is change the class functions, you don't have to worry about renaming all the function calls in your site from MySql to Oracle.
    Yep, that is indeed the way to go. The user of a class should not be made aware of the internals of that class in any way (encapsulation principle). This also means that your class name, method names and the likes should be as neutral as possible.

    Not that in your example there is a technical requirement to change the method names if you would change the internals from MySQL over to Oracle (morally you are even forbidden, remember the 'programming against interfaces' agreement).
    It would however be very confusing for whoever would use your class, let alone the poor developer that would continue the development after you received your big promotion.

    Hope it helps .....
    Last edited by spoorw8er; Oct 15, 2001 at 07:41.

  18. #18
    Database Jedi MattR's Avatar
    Join Date
    Jan 2001
    Location
    buried in the database shell (Washington, DC)
    Posts
    1,107
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Wow! Great thread! I'll try and comment on a few things I've pulled from it.

    -- Re: Standards --
    One thing I've learned is that if you spend less than 75% of your time *planning and designing* an application then you've done something wrong. Highly detailed specifications not only enable you to easily design the modules but also QA them later (try testing a complex piece of accounting software when it’s obvious that the developers don’t know how the taxing and discount scheme works!).

    -- Re: OOP --
    I think OOP in web-apps are over-rated. Most, if not all, web applications have a single thing in common – the user ID or session ID. Since PHP doesn’t have any sort of shared memory for inter-process communication I can’t have a ‘global’ object which can be read from every script. I have to go through the overhead of creating the object each and every time the script is run!

    I can see how, in limited use, it can be pretty useful. The problems I run into, however, are that most classes I find are based upon the following:
    1) PHP
    2) MySQL

    So, if I’m not using MySQL I have to re-write it to fit my RBMS. Also, if my data requirements vary AT ALL I have to do a significant amount of code changes to make it work.

    -- Re: DB Abstraction Layer --
    I don’t think that the DB abstraction layer is a good example of OOP programming. I hear ‘so this way we can change backends on the fly by throwing a switch!’ but that, in practice, will almost never, ever happen.

    Every RDBMS has their own sub (and super!) set of SQL. Some functions exist in one which do not exist in the other. Inserts using a monotonic series (e.g. auto increment) are different on each RDBMS. Some support stored procedures, others not. When you change RDBMS’ you *must* change your application embedded SQL or it won’t work.

    Doing a global find-and-replace for mysql_query is trivial compared to changing every instance of INSERT INTO … VALUES( NULL, … ) that uses an auto_increment in MySQL to INSERT INTO … VALUES( some_squence.nextval, … ) which uses a Sequence value in Oracle.

    If you *do* wish to create a DB class your best bet is to have member functions for each common type of SQL operation – insert, delete, update, select.

    So, you have something like:
    $db->insert( “tablename”, “value1”, “value2”, … ); // something like this
    or
    $db->delete( “tablename”, “somecolumn”, “where_is_equal_to_this_value” );

    The only problem is when you have a more complicated SELECT (e.g. subquery, joins) – so you are forced to more or less *waste* the OOP by doing:
    $db->query( “SELECT …” );

    So there is the illusion of having the advantages of OOP but few (if any) real advantages.

    What I *would* suggest is looking at stored procedures, triggers, and Java-In-The-Database.

    Stored procedures are (strangely enough ) bits of SQL stored inside the database. SPs allow you to turn the declarative SQL into procedural code! Think of a SP as a function in PHP. They take parameters and return values and somewhere in the middle can have while loops, case statements, etc.

    Take our insert statement above. You can go back to the query syntax but create a ‘user_insert’ stored procedure:
    $db->query( “EXEC user_insert_sp, ‘username’, ‘password’, ..” );

    Unfortunately this does not lend to much code reuse unless you are very clever with your SP design and can create an extensible SP to handle an arbitrary table.

    However there are major advantages to this in that most, if not all, RDBMs’ support SPs in one way or another. If you were to port the app to something else you would have to re-write your stored procs but the application code would remain constant.

    Of course, there are performance implications of SPs (they are much faster than ad hoc SQL) which further make them more attractive.

    Java in the DB is another thing most enterprise RDBMS’ support. Basically they have their own JVM inside the DB which allows you to create, execute and store java data natively in the database. This can allow for further platform independence since java on one DB is identical to java on another db (standards at work! finally!).

    So you create a user class and can natively store the class data in the DB – it helps for when you have things that you can define on a class basis but that do not necessarily lend to relational storage.

    Also, changing the DB without tailoring your SQL is doing the DB a vast disservice. They have spent years perfecting their optimizer and performance features and you’re basically designing for the least common denominator. Instead of a DB class why not just use ODBC?

    Oh yeah, it is horribly slow! Same thing with keeping the SQL the same. You need to have an intimate knowledge of the RDBMS you are porting to so that your application and the database can perform to their highest potential. Anything less would be a waste of your time and more importantly, a waste of your customer’s money.

  19. #19
    SitePoint Enthusiast
    Join Date
    Oct 2001
    Location
    London
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Data abstraction

    Updated: 15th October 2001

    Data Abstaction

    A few moments after sending my last post, it occurred to me that the principle behind renaming the MySql class as Database is called 'data abstraction.'

    Since everyone these days is busy, busy, busy, I will continue to clarify key object-oriented concepts so that people with a procedural background can read this thread and 'get it' quickly.

    Here are two more quotes to clarify the 'data abstraction' concept:

    1. Data abstraction at the level of defining what the class does.

    "Data abstraction is defined as extracting from the abundance of information-related data. It is important that related data be kept together for easier manipulation. It is equally important, however, to abstract the generic (or common) data from specific details. A personnel system will be easier to implement if it uses "people," rather than specifics such as "Tom," "Dicket," and "Harriet."

    (p.24, Object-Oriented Analysis & Design, Andrew Haigh)


    2. Data abstraction at the level of defining what goes into the class.

    "The world is a complicated place. To deal with that complexity, we form generalizations, or abstractions, of the things in it. For example, consider the abstraction of a person. From the point-of-view of a university, it needs to know the person's name, address, telephone number, social security number, and educational background. From the point-of-view of the police, they need to know a person's name, address, phone number, weight, height, hair color, eye color, and so on. It's still the same person, just a different abstraction, depending on the application at hand.

    Abstraction is an analysis issue that deals with what a class knows or does. Your abstraction should include the features, attributes and methods that are of interest to your application and ignore the rest. That's why the abstraction of a student would include the person's name and address, but probably not his height and weight. People often say that abstraction is the act of painting a clear box around something or they say abstraction is the act of defining the interface of something. Either way, you are defining what the class knows and does."


    3. Here’s a better description of encapsulation and why it is necessary.

    "Although the act of abstraction tells us that we need to store a student’s name and address as well as be able to enrol students in seminars, it doesn’t tell us how we are going to do this. Encapsulation deals with the issue of how you intend to modularise the features of a system. In the object-oriented world, you modularise systems into classes, which, in turn, are modularised into methods and attributes. We say that we encapsulate behaviour into a class or we encapsulate functionality into a method.

    Encapsulation is a design issue that deals with how functionality is compartmentalized within a system. You shouldn’t have to know how something is implemented to be able to use it. The implication of encapsulation is that you can build anything anyway you want, and then you can later change the implementation and it will not affect other components within the system (as long as the interface to that component does not change).

    People often say encapsulation is the act of painting the box black: You are defining how something is going to be done, but you are not telling the rest of the world how you’re going to it. For example, consider your bank. How does it keep track of your account information, on a mainframe, a mini, or a PC? What database does it use? What operating system? It doesn't matter, because it has encapsulated the way in which it performs account services. You just walk up to a teller and do whatever transactions you want. By hiding the details of the way it has implemented accounts, your bank is free to change that implementation at any time, and it shouldn’t affect the way services are provided to you."


    4. More on information hiding

    "To make your applications maintainable, you want to restrict access to data attributes and some methods. The basic idea is this: If one class wants information about another class, it should have to ask for it, instead of taking it. When you think about it, this is exactly the way the real world works. If you want to learn somebody’s name, what would you do? Would you ask the person for his name, or would you steal his wallet and look at his ID? By restricting access to attributes, you prevent programmers from writing highly coupled code. When code is highly coupled, a change in one part of the code forces you to make a change in another, and then another, and so on."

    (pp.144-145, The Object Primer, 2nd. Ed, Scott W. Ambler)


    Recap about main Object-Oriented concepts

    So to recap, the key principles involved in object-oriented design are:

    1. Abstraction (the essential generic characteristics).
    2. Encapsulation (how we group all the related concepts into one class/component).
    3. Information hiding (the restriction of external access).


    And a final example to bring it all together:

    When we talk about a car... "the abstraction is how you work with the wheel, pedals, and gearshift to drive a car. Encapsulation enables various car makers to provide a consistent interface, although each brand of car is build differently. Information hiding is represented by the fact that, although the oil is kept at a specific pressure within the engine, the driver doesn't know what the exact pressure is. In other words, information about the oil is hidden from the user."


    This is why the above principles are so important…

    "For example, say the programmer for class 'Student' knows the attribute list_of_students in the class 'Seminar' was implemented as an array. The programmer decides to have the instance of ‘Student’ add itself in the first available array element. A few months later, somebody else comes along and decides to reimplement list_of_students as a linked list to use memory more efficiently. This is a reasonable and likely change. Unfortunately, the second programmer doesn’t know the first programmer was directly updating the array of students; consequently, the university information system crashes.

    Had access to the attribute list_of-students been restricted, the programmer of 'Student' wouldn’t have been able to update its value directly. Therefore, the programmer would have had to write code to ask seminar objects to add a student object to its list. If this had been the case, when list_of_students was changed into a linked list, a problem would not have occurred (when the second programmer changed the implementation of the attribute, she would also have modified any methods of 'Seminar' that accessed it). By hiding the information (the seminar list) and encapsulating how students are enrolled in courses, you are able to keep the abstraction the same."

    (p.145, The Object Primer, Scott W. Ambler)


    Mike Mindel
    Wordtracker
    Last edited by mikemindel; Oct 15, 2001 at 14:24.

  20. #20
    Database Jedi MattR's Avatar
    Join Date
    Jan 2001
    Location
    buried in the database shell (Washington, DC)
    Posts
    1,107
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    spoorw8er's (interesting name!) example of SQL stuff is kind of like what I was talking about.

    However, SQL is such a rich language that creating a member function for each certain flavor of SELECT is impossible.

    Insert can do a couple of different things:
    SELECT * FROM sometable INTO someother_table
    -- will create a new table with the query results

    INSERT INTO sometable ( SELECT * FROM someothertable )
    -- will insert rows from one table into another

    INSERT INTO table1 VALUES( ... )
    -- will only work if you specify all columns in the table or not-null ones

    INSERT INTO table1( col1, col2 ) VALUES( ... )
    -- inserting to specific columns

    etc.

    When you create a 'query' member function you are essentially destroying the encapsulation and hiding that OOP is used for. You're giving a client the express ability to do *anything* in the database.

    In that case, it is no better than simply performing regular mysql_queries. The only thing I can think of that having a class saves is error detection (I would have to trap each mysql_query).

    Even then I see a lot of this:

    PHP Code:
    $some $db->query( ... );

    if( 
    $some ) {
      
    $thing $db->fetch_array$some );
      if( 
    $thing ) {
        echo 
    "stuff, $thing[stuff]";
      } else {
        echo 
    "broke!";
      } 
    // end if
    } else {
      echo 
    "broke!";
    // end if 
    What is wrong with this picture? You're splitting up the error detection partly between the class and the application.

    Why not do something like this:
    PHP Code:
    function insert$tablename$value, &$db_conn ) {
      
    query
      
    if not broken
        
    return 1
      
    else
        return 
    0
    // end function insert

    if( $db_insert( ... ) ) {
      echo.
    } else {
      
    something broke!
    // end if 
    If you want to take it to the next step, you should create a db_error class.

    Instead of returning 1 or 0, return 1 on success otherwise return the error code returned from the RDBMS.

    Then you pass that code to your error class which will look up what error 1234 is and notify you accordingly.

    Also,

    What is this:
    PHP Code:
      $bob $db->query"SELECT joe FROM" );
      echo 
    $bobjoe ]; 
    You're touching the protected DB data directly.

    PHP Code:
      $bob ...;
      
    $db->print_result$bob ); 

  21. #21
    SitePoint Enthusiast
    Join Date
    Oct 2001
    Location
    London
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Focusing the thread

    Ok,

    (On Database Abstraction Layers and PHP)

    I used to code all database calls within the body of each PHP script. But continually writing something like:

    PHP Code:
    $dbh mysql_connect ($mysql_host$mysql_username$mysql_password
    or die (
    sprintf ("Cannot connect to MySQL [%s]: %s",
     
    mysql_errno (), mysql_error ())); 
    @
    mysql_select_db ($mysql_database
    or die (
    sprintf ("Cannot select database [%s]: %s"mysql_errno (), mysql_error ())); 
    $sth = @mysql_query ("SELECT * FROM tblTablename"$dbh
    or die (
    sprintf ("Cannot execute query [%s]: %s"mysql_errno (), mysql_error ())); 

    $i 1;        
    while (
    $row mysql_fetch_object ($sth)) {
           
    $host[$i] = $row->Host
        
    $get[$i] = $row->Get
        .
        .
    }
    mysql_free_result ($sth);
    mysql_close(); 
    was driving me nuts. With a database abstraction class that I adapated, I can now just write:

    PHP Code:
    $some_array $this->mysql->query("SELECT * FROM tblSomeTable"); 
    and the abstraction layer figures out if a connection is open. If it is, then there is no overhead in opening a new connection and if it isn't, then it opens it without an error!

    This just saves me *hours* of work. Literally. The same applies to the template class that I wrote. Separating code from html using the template class is a real time saver.

    Catching all mysql errors, printing out all mysql statements is also a great debugging tool. Especially if you're just wanting to see what sql statements are running through the abstraction layer so you can see what is going on. Personally I wouldn't leave home without it. But that's just me.

    ----------------------------------------------------------

    Just to focus this thread a bit more. I think we should assume that most (not all) PHP developers who work with classes will probably use a database abstraction layer (database object) and template system (web page display object).
    Last edited by mikemindel; Oct 15, 2001 at 10:00.

  22. #22
    SitePoint Enthusiast spoorw8er's Avatar
    Join Date
    Oct 2001
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Mattr,

    Good to have some alternative views on the subject. Some comments on the comments

    edit: just saw Mike's post (he's a faster typer than me it seems).
    Well, that is one very good reason to go for OO. It does save you time in developing the core part of your app, you can focus on the job at hand when dealing with a user for instance, not write over and over the same lines of code that check for a database-connection, sets it up, checks for errors, ..... Hey, it works for me


    1. Standards
    I agree completely, most of the time should be spent in design. I'm personally not a big fan of saying 75%, I find it does depend a bit on the size of the project and the technical side of things, but if you're not spending at least half of your time in design, chances are you'll run into trouble during implementation.
    And as you indicated, a good design is not only the basis for your coding, but also for your testing (and the scripts you might have to devleop to automate this....).

    2.OO
    Granted, for many web-apps OO seems a bit over the top. OOP-code does bring along some overhead when executing. Furthermore, taking the OO approach adds overhead to the your complete development process.
    So before you start a project, you should always consider carefully if it is worth taking the overhead in exchange for the benefits (and some of those are only benefits in larger projects).

    The example you give where you have to re-create the object on every scriptrun is somewhat misleading though. Compare webb-apps to 'normal' application environments, things are actually quite similar. Every instance of an application instantiates his objects.
    The fact that PHP has no shared-memory is not a drawback of OO, just a technical issue in the current PHP implementation.

    And be careful with the term web-apps. Some of these things are pretty complex from an architectural viewpoint and definitely could benefit from using the OO-approach.

    3. DB Abstraction
    Well, that's pretty much the standard discussion: do you stick to the common elements of SQL or do you want to make use of the extra's some suppliers provide?
    I find this is in many cases a difficult balancing act. Depends a bit on the type of project too.
    If you are almost 100% sure your app will only run on one particular database engine, by all means, make as much use of the extra's as you can (I personally would find it a bad decision if you didn't in those circumstances).
    But that does not have to mean you shouldn't abstract the database-layer. One of the principles of OO is to group similar (note: similar, not identical) functionality, this is what abstraction means.

    Doing a global find-and-replace for mysql_query is trivial compared to changing every instance of INSERT INTO … VALUES( NULL, … ) that uses an auto_increment in MySQL to INSERT INTO … VALUES( some_squence.nextval, … ) which uses a Sequence value in Oracle.
    Well, I would argue it is just the opposite. If I have a class encapsulating the database that exposes an insert_method, the only place I have to change code is in that method, not do a find and replace in several scripts.

    I agree that stored procedures are definitely worth considering when available in your RDBMS, but I would again urge you to encapsulate and abstract these with a database-class.
    Taking your example, you could create the method also like this:
    PHP Code:
    $my_db = new Database();
    $my_db->use_stored('new_user''username,password');

    class 
    database {
       
    // members and stuff
       
    ....
       
    // constructors and so on
       
    ....
       
    // use stored procedure method
       
    function use_stored ($sp_name$sp_values) {
          switch 
    $sp_name
          
    case 'new_user':
             
    $values explode (","$sp_values);
             
    query("EXEC sp_insert_user, $values[0]$values[1]");
           case 
    'new_page':
              .....
       }

    Yep, I know, switches and cases do seem a bit of a drag. But this is actually a quite common pattern when using objects and the likes. Take a look at the average message-pump code in the Microsoft MFC (oh no, not MS again.... well others use it quite regularly too, just can't think of any names at this moment ;^).

    And yes, while you can write a number of methods for the more straightforward stuff, there are also the complex cases to consider. Well, like I said, pure OO would be magical, but in real life you sometimes have to make a compromise.
    Last edited by spoorw8er; Oct 15, 2001 at 09:20.

  23. #23
    SitePoint Enthusiast
    Join Date
    Oct 2001
    Location
    London
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    We just have to compromise!

    Here's an interesting issue regarding the use of the database abstraction layer:

    Take the following description of a small object oriented system from The Object Primer:

    "Consider the design of an information system for a university. Taking the structured approach, you would define the layout of a database and the design of a program to access that data. In the database would be information about students, professors, rooms, and courses. The program would enable users to enrol students in courses, assign professors to teach courses, schedule courses in certain rooms, and so on. The program would access and update the database, in effect supporting the daily business of the school.

    Now consider the university information system from an object oriented perspective. In the real world, there are students, professors, rooms, and courses. All of these things would be considered objects. In the real world, students know things (they have names, addresses, birth dates, telephone numbers, and so on) and they do things (enrol in courses, drop courses, and pay tuition). Professors also know things (the courses they teach and their names) and they do things (input marks and make schedule requests). From a systems perspective, rooms know things (the building they’re in and their room number) and should be able to do things, too (such as tell you when they are available and enable you to reserve them for a certain period of time). Courses also know things (their title, description, and who is taking the course) and should be able to do things (such as letting students enrol in them or drop them).

    To implement this system, we would define a collection of classes (a class is a generic representation of similar objects) that interact with each other. For example, we would have 'Course,' 'Student,' 'Professor,' and 'Room' classes. The collection of these classes would make up our application, which would include both the functionality (the program) and the data.

    As you can see, the OO approach results in a completely different view of what an application is all about. Rather than having a program that accesses a database, we have an application that exists in what is called an object space. The object space is where both the program and the data for the application reside."

    (p.3, The Object Primer, Scott W. Ambler)

    _____________________________________________________________________________________________

    Now if we were to implement the above system in PHP, how would 'Course', 'Student', 'Professor' and 'Room' know about themselves from page to page anyway?

    Where is the following information going to be held?

    1. The course the professor knows.
    2. The building that the room knows its in.
    3. How many rooms the building has empty.

    Since we are not using objects in a persistent way, then each object is going to be instantiated again every time a web page is accessed and presumably the data part of this program/data encapsulation will actually reside in a database (and probably MySql).

    (This, assuming that we have not serialized the object and passed it across from one web page to another using a form - which is probably a real bandwidth waster anyway).

    If we are accessing data through these objects, they themselves will presumably be using the 'database' abstraction layer to get and store their information. I mean, we don't have a persistent ODBMS that ties in with PHP so we have to resort to RDBMS procedures.

    So the 'database' abstraction layer needs to be present in 'all' second, third, fourth... level objects in our Web system. (First level being the database object itself, and any other object that doesn't depend on any other object).

    If we have 20-30 objects, that's 20-30 abstraction layers. It's very messy... unless of course we opt for step 3 in the article at the top of this post - we define a global: $database = new database_class(); in the initial global script. Then for each class, we provide a local alias to that global: $this->database = $GLOBALS["database"]; Otherwise we are going to instantiate the abstraction layer 20 times rather than time share the one connection!

    I think... that with PHP and objects we have to find a 'compromise' solution for object-oriented programming in large projects. We simply can't be pure OO. We can be OO like.

    Mike Mindel
    Wordtracker
    Last edited by mikemindel; Oct 15, 2001 at 10:08.

  24. #24
    SitePoint Enthusiast
    Join Date
    Oct 2001
    Location
    London
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Now we're motoring...

    In a previous post, coupling was mentioned. Here is a description, again, by the very eloquent Scott. Ambler. If anyone needs a decent book on Object Oriented programming, this one really cuts it. I'm very impressed.

    I think this description of coupling holds the key to the current problem.

    "Coupling is a measure of how much two items, such as classes or methods, are interrelated. When one class depends on another class, we say they are coupled. When one class interacts with another class, but doesn’t know any of the implementation details of the other class, we say they are loosely coupled. When one class relies on the implementation (that is, it directly accesses the data attributes of the other), we say they are highly coupled.

    Previously, I discussed the sample of how the class 'Student' could implement the 'enroll' function: It could directly access the attribute list_of_students in 'Seminar,' or it could send send 'Seminar' objects a message asking it to enrol the student in the seminar. Directly accessing and updating the attribute list_of_students might save a few CPU cycles and run a little quicker, but as soon as the implementation of that attribute changes, you would need to modify the code in 'Student.' As you saw, this was not very good. The basic problem is when two classes are highly coupled, a change in one often requires a change in the other. This, in turn, could require a change in another class, and then another, and then another, and so on. High coupling is one of the main reasons such a large maintenance burden exists (the need for software organizations to invest money in the support, operation, and enhancement of existing hardware.) What should be a simple maintenance change can often create months of work, if it can be done at all. It is amazing how much code is out there that nobody is willing to touch because they’re afraid of breaking it.

    Every so often, developers are seduced by the dark side of the force and decide to write code that is highly coupled. This approach only makes sense when you are truly desperate to cut down on the processing overhead in your system. For example, database drivers are often highly coupled to the file system of the operating system on which the database runs. If you can save a few milliseconds accessing data, it quickly adds up when you are accessing hundreds of thousands of objects."

    (p.172, The Object Primer, 2nd. Ed, Scott W. Ambler)

    Now this is different from 'association':

    "In the real world, objects have relationships, associations, to other objects. The relationships between objects are important because they help us to define how they interact with each other. For example, students TAKE courses, professors TEACH courses, criminals ROB banks, politicians KISS babies, and captains COMMAND starship. Take, teach, rob, kiss, and command are all verbs that define associations between objects. You want to identify and document these relationships, therefore, you can gain a better understanding as to how objects interact with one another."

    (p.152, The Object Primer, 2nd. Ed, Scott W. Ambler)


    This is all very, very important stuff. Let's go back to the original problem. We had a class that looked like this:

    PHP Code:
    class test_class {
        
        function 
    test_class() {
        
            
    // Replace with contents of the create_references file. This will make
            // local aliases of all global variables including objects such as mysql
            // so we don't have to keep creating new instances.        
            
    require("classes/create_references.inc");
        }

        function 
    test_method() {
            
    // Requires a user variable
            
    $remote_user $this->user->remote_user;
            
            
    // Requires a connection to the mysql method
            
    $this->mysql->query("some query that uses $remote_user");

            or 
    alternatively:

            
    $this->mysql->query("select * from some table where user = {$this->user->remote_user}");
        
            
    Then update the statistics:

            
    $this->statistics->update_statistics();

            
    Maybe update your basket too:

            
    $this->basket->add_item($item_name$quantity);
        }


    It's highly coupled code. Change one thing and another might break, and another and so on. And it's badly designed! Object relationships have not been defined clearly. Nor are the objects separated into levels of abstraction. In short. A mess. Bleeurgh.

    But I think there's now a way out. The first clue (as in the previous email) is in the quote "the object space is where both the program and the data for the application reside."

    Here is my conclusion:

    1. The code and the data storage mechanism should be as highly coupled as possible. Just like the database drivers and the file system of the OS in the coupling quote above. But all other objects should follow the principles of abstraction, encapsulation, and information hiding.

    Basically, I think we want to move as close to the principle of an ODBMS as possible whilst using an RDBMS system. So I think that a global database object with local aliases in each class is actually a really good idea. It at least gives the illusion of persistent data storage. After all, each method in each object will reference different tables in the RDBMS. A user object will reference user tables for example. But all other objects that communicate with the user object need not concern themselves with how the user gets its information. All they want to know is what the user information will provide them. So... highly couple the objects with their data storage mechanism to give the illusion of object persistence.

    2. Make sure you have implemented your first level classes (those classes that don't rely on any other objects). E.g. the database abstraction layer, the display template class, the fetch a web site class.

    3. Then make sure that you don't use high coupling ever again! Or if you have to, only if it's an absolute necessity. (You probably have to use loose coupling - which is more an association).

    So. Let's take another look at how we could reorganize the above code. First of all we code our first level classes:

    PHP Code:
    Define first level classes:

    class 
    database_class {
         
        
    Database abstraction stuffQueryconnect,
        
    blahblahblah.
    }

    class 
    display_class {
     
        
    Take template file as parameterimport it,
        
    replace tags with information you want
        displayed 
    and then print to page.

    }

    class 
    fetch_class {

        
    Perhaps some methods to grab web pages

    Note that none of these classes rely on any other classes.

    Second level classes. They have the coupled database abstraction layer and perhaps also associations with other classes on their level.


    PHP Code:
    class user_class {

            function 
    user_class {
            
    // Couple with the global database object so
            // we don't end up instantiating the database
            // hundreds of times.

            
    $this->database $GLOBALS["database"];
        
            
    Maybe we should instantiate the basket class
             
    here tooAfter allwe only update the basket
             using user details
    The user has a basket         
            making user a composite object
    .

            
    $this->basket = new basket();
        
            
    Maybe we should instantiate the statistics 
            
    class here tooAfter allit's only
            the user that would update it.
            $this->statistics = new statistics();

        }

        This is an important shift. No longer do
        we directly access the properties of the
        user class. Now we have methods for 
        storing and retrieving user based information.

        e.g. get_contact_details() and
        store_contact_details()

        We are no longer coupling the user class!
        Yipeee! Thanks to encapsulation.

        function store_contact_details() {
            // Do some stuff but also access
            // the basket.
            $this->basket->store_items(item, quantity)
            $this->statistics->update_statistics(whatever, whatever);
        }
    }

    class basket() {

        function basket() {
            Couple with database again
        }

        Functions to add, remove elements from
        the basket. 
    }

    class update_statistics() {
        Again, couple the database object and then
        provide methods for updating the statistics.

    So now we can rewrite our problem test (third level)
    class. I say third-level but it is somewhat arbitrary. I'm just calling third-level anything that receives other classes by reference and try to do as few of those as possible.

    PHP Code:
    class search_class {
        
        function 
    search_class() {
        
        
    // Couple with the global database object so
        // we don't end up instantiating the database
        // hundreds of times.
        
    $this->database $GLOBALS["database"];
        }

        function 
    perform_search(&$user) {

        
    None of this stuff is necessary any more as
        
    it is handled by the composite user object.
        
    Composite means an object that holds one or
        
    more other objects.

        
    Goodbye--> $remote_user $user->get_user();
        
    Goodbye--> $this->mysql->query("select * from some table where user = '$remote_user'");
        
    Goodbye--> $statistics->update_statistics();
        
    Goodbye--> $user->update_basket($item_name$quantity);

        
    Instead we can just call a method of the
        user object 
    and it will do all the work.

        
    $some_user_info $user->register_this_search();

        
    Instantiate the class that will do the search 
        
    for us
        $search 
    = new search_class();
        
    $search->perform_search(some query);
        }


    So... Maybe that's the answer.

    1. A process of high database/object coupling.

    2. Completely encapsulate and abstract all other objects.

    3. Be very aware of your layers. Try and keep all objects that don't rely on other objects in your first layer.

    4. Group objects that belong with other objects together (basket with user). These presumably will be of the same layer. E.g. basket class will be on same layer as user class.

    5. Only pass one or two references in your method calls at higher levels.

    6. And last but certainly *not* least. Make sure you do some kind of design. Draw all your objects on a page (if you can't be bothered with UML) and draw lines from one to another, showing how they interact. Which object depends on which. How else would you know that you could abstract the basket and statistics class into the user object otherwise!

    All this means that your major functionality operates at the lower layers, leaving your higher level code/classes with maybe 3-4 lines per method.

    Notice how it's no longer necessary to think that all objects need to know about all other objects. But if you're coming from a procedural/function background, it's easy to see how you could fall into the conceptual trap at the top of this thread.

    It's in the design people!

    Ok. Thoughts please gentleman. I know this thread is getting long, but hopefully we're clearing things up here. I accept I still may be wrong, but I also think I've made a step forward in this.

    Mike Mindel
    Wordtracker

    P.S. (Updated 16th October 2001). I've just had another thought. Since there are some variables that are simply used again and again by a php system. E.g. say you weren't using PHP user based authentication, and just the .htaccess and .htpasswd files. In which case the $GLOBALS["REMOTE_USER"] variable would hold the username. It would be a real pain to store this in the user object and then make calls like $user->get_remote_user all the time.

    I think that along with database coupling, we should allow certain global variables that naturally persist within objects e.g. REMOTE_USER, REMOTE_IP, todays_date by creating the local references talked about in part 3 of the first article in this thread. (Without making local aliases to the objects).

    Or alternatively, if you are using sessions, then you can specify global variables that will persist anyway. I dunno. Maybe certain objects should persist using sessions. Maybe all the objects could persist in the sessions so you wouldn't have to keep instantiating them over and over! Is this a bandwidth saver or buster?
    Last edited by mikemindel; Oct 15, 2001 at 18:00.

  25. #25
    Database Jedi MattR's Avatar
    Join Date
    Jan 2001
    Location
    buried in the database shell (Washington, DC)
    Posts
    1,107
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Re: Focusing the thread

    Originally posted by mikemindel
    (On Database Abstraction Layers and PHP)
    Mike, that is exactly 100% correct why everyone (well, most people), including myself, use an abstraction layer.

    However, it exhibits approximately ZERO of the virtues of OOD and OOP which we've been discussing which is why I suggested it is a poor example to show someone who may not know.

    To a person not 'in the know' when you say 'magical DB abstration' they believe you since they've not used every RDBMS so they don't know how truely different they are.

    As has been said, in a utopian world, every RDBMS would have the same SQL syntax and the only difference would be the name of the connection. However, in today's world that is sadly not the case (esp. for anyone porting an application!!!).


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
  •