SitePoint Sponsor

User Tag List

Results 1 to 20 of 20
  1. #1
    SitePoint Wizard REMIYA's Avatar
    Join Date
    May 2005
    Posts
    1,351
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Exclamation Smart Data Access Object

    This Data Acess Object has several benefits.
    1. Smart database saving (saving database load)
    2. Methods creation on the fly
    3. Change listeners (= Observers, EventListeners)
    4. Method chaining
    5. Single instance of DAO in every moment
    6. Possibility to easy verify user input according to data type (string, bool, email, etc) using validators (not shown here)
    PHP Code:
    /**
     * <br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/">Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 License</a>.
     * @package MVCS
     * @copyright &copy 2007 Remiya
     */
    abstract class MVCS_DAO{
        private 
    $fields = array();
        private 
    $states  = array();
        private 
    $types  = array();
        private 
    $values = array();
        private 
    $listeners = array();
        final private function 
    __construct($db){
            echo 
    "Loading DAO...<br>";
            
    $this->__load_structure();
            foreach(
    $this->__structure as $field=>$type){
                
    $this->fields[]=$field;
                
    $this->types[]=$type;
            }
            
    $this->__load();
        }
        abstract public static function 
    getInstance();
        abstract public function 
    __load_structure();
        final private function 
    __call($method$arguments){
           if(
    in_array($method,$this->fields)==false)trigger_error('ERROR: Field <b>'.$method.'</b> not in '.get_class($this).' structure!',E_USER_ERROR);
           if(
    count($arguments)==0){
               return 
    $this->__get($method);
           }else{
               
    $this->__set($method,$arguments[0]);
               if(isset(
    $this->listeners['on_'.$method])){
                   
    $this->__update();
                   foreach(
    $this->listeners['on_'.$method] as $listener){
                       echo 
    "Updating listener ".$listener."<br>";
                       
    //$listener->update();
                   
    }
               }
           }
           
           return 
    $this;
        }
        final private function 
    __set($field,$value){
            echo 
    "Setting <b>$field</b> to $value...<br>";
            
    $pointer array_search($field,$this->fields);
            
    $this->values[$pointer] = $value;
            
    $this->states[$pointer] = "changed";
        }
        final private function 
    __load(){
            echo 
    "Loading DAO from database...<br>";        
        }
        final public function 
    __update(){
            if(
    in_array("changed",$this->states)){
                
    $fields = array();
                for(
    $i=0;$i<count($this->fields);$i++){
                    if(
    $this->states[$i] == "changed"){
                        echo 
    "Changes found in ".$this->fields[$i]."<br>";
                        
    $fields[$this->fields[$i]] = $this->values[$i];
                    }
                }
                echo 
    "Saving the fields <b>".implode(",",array_keys($fields))."</b> of DAO in database...<br>";
                
    $this->states = array();     
            }else{
                echo 
    "No changes found...<br>";
            }
        }
        final private function 
    __get($field){
            echo 
    "Getting <b>$field</b>...<br>";
            
    $pointer array_search($field,$this->fields);
            return 
    $this->values[$pointer];        
        }
        final public function 
    add_listenter($event,$listener){
            echo 
    "Adding listener ".$listener." updated on ".$event."<br>";
            
    $this->listeners[$event][] = $listener;
        }
        final public function 
    __destruct(){
            
    $this->__update();
            echo 
    "Deleting DAO...<br>";
        }

    Extending MVCS_DAO
    PHP Code:
     class User extends MVCS_DAO{
        private static 
    $_instance;
        public static function 
    getInstance(){
            if (
    null === self::$_instance) {self::$_instance = new self($db);}
            return 
    self::$_instance;
        }
        function 
    __load_structure(){
            
    $this->__structure = array(
                
    "username"=>"string",
                
    "password"=>"string",
                
    "firstname"=>"string",
                
    "lastname"=>"string"
            
    );
        }

    Usage:
    PHP Code:
    // Creating a new User
    $user User::getInstance();
    // Adding listeners to be updated when the first name is changed in the database
    $user->add_listenter("on_firstname","FIRST NAME LISTENER 1");
    $user->add_listenter("on_firstname","FIRST NAME LISTENER 2");

    // Changing the user's username to TOMMY and forcing the saving to database
    // If no update is forced the saving will occur on object destruction
    $user->username("TOMMY")->__update();

    // Chaging the user's username and last name and forcing saving to database
    // If no update is forced the saving will occur on object destruction
    // Changing first name notifies the listeners
    $user->firstname("Tom")->lastname("Curtis")->__update();

    // Example of getting parameters
    echo "User ".$user->username()." is ".$user->firstname()." ".$user->lastname()."<br />";

    // Example forcing update, that doesn't get saved to the database, because no change in the User properties are found
    $user->__update();

    // On destruction of object, the object is checked for changes
    // If no changes found object dies, else object is saved to database
    // and object dies 
    And here is the output from the example:
    Loading DAO...
    Loading DAO from database...
    Adding listener FIRST NAME LISTENER 1 updated on on_firstname
    Adding listener FIRST NAME LISTENER 2 updated on on_firstname
    Setting username to TOMMY...
    Changes found in username
    Saving the fields username of DAO in database...
    Setting firstname to Tom...
    Changes found in firstname
    Saving the fields firstname of DAO in database...
    Updating listener FIRST NAME LISTENER 1
    Updating listener FIRST NAME LISTENER 2
    Setting lastname to Curtis...
    Changes found in lastname
    Saving the fields lastname of DAO in database...
    Getting username...
    Getting firstname...
    Getting lastname...
    User TOMMY is Tom Curtis
    No changes found...
    No changes found...
    Deleting DAO...

  2. #2
    SitePoint Evangelist
    Join Date
    Mar 2005
    Posts
    421
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm curious as to why you are using double underscores on method names - i thought they were reserved by php as possible magic methods?

  3. #3
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You implement the class as a singleton, yet it seems to manage a single record. That is going to give you trouble.

  4. #4
    SitePoint Wizard REMIYA's Avatar
    Join Date
    May 2005
    Posts
    1,351
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    You implement the class as a singleton, yet it seems to manage a single record. That is going to give you trouble.
    In what aspect?

  5. #5
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by REMIYA View Post
    In what aspect?
    Like, if you'll ever have to work with more than one record at a time.

  6. #6
    SitePoint Wizard REMIYA's Avatar
    Join Date
    May 2005
    Posts
    1,351
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I see your point now. Yes, this is a simple example with one record.
    I am thinking on how to implement the multiple records now. May be they will be defined also in the structure.

    Any ideas welcome.

  7. #7
    SitePoint Wizard REMIYA's Avatar
    Join Date
    May 2005
    Posts
    1,351
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The structure should be read like this

    function __load_structure(){
    $this->__structure = array(
    "username"=>array("type"=>"string","table"=>"users"),
    "password"=>array("type"=>"string","table"=>"users"),
    "firstname"=>array("type"=>"string","table"=>"users"),
    "lastname"=>array("type"=>"string","table"=>"users"),
    "lastname"=>array("type"=>"string","table"=>"users"),
    "photos"=>array( "type"=>"Photo"," table"=>"photos", "by"=>"username"),
    "albums"=>array("type"=>"string","table"=>"users"),
    );
    }

  8. #8
    <?php while(!sleep()){code();} G.Schuster's Avatar
    Join Date
    Mar 2007
    Location
    Germany
    Posts
    428
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Maybe a primary key could help you with the singleton problem.
    You could use a singleton object for ech row identified by its unique ID.
    That's only what came to my mind after reading the thread, didn't really think it over so it may be stupid crap.

  9. #9
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You are thinking of an Identity Map but personally I don't believe that pattern has much use with PHPs architecture (everything dies at end of request, even bacteria) so it would be fruitless...

    Unless of course, you use some sort of cache, but your server would need to have that supported.

  10. #10
    SitePoint Addict Jasper Bekkers's Avatar
    Join Date
    May 2007
    Location
    The Netherlands
    Posts
    282
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Couple of notes on the implementation.
    * Why declare everything, even private methods, as final? Final private methods don't really make any sense.
    * Nor do abstract static methods.
    * Why does __load_structure start with two underscores and is public? (You shouldn't start your own methods with two underscores anyway.
    * I don't know how you implemented the data validation part, but it really shouldn't be coupled to a data access object.
    * DAO decouple the actual data (using DTOs, Data Transfer Objects) from the storage mechanism while your implementation actually keeps track of the data itself.
    * Think of data migration and how you're going to handle changes in the data model it's an important aspect that is often overlooked, Ruby On Rails could be a source of inspiration here.

  11. #11
    SitePoint Zealot
    Join Date
    Sep 2005
    Posts
    122
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston View Post
    You are thinking of an Identity Map but personally I don't believe that pattern has much use with PHPs architecture (everything dies at end of request, even bacteria) so it would be fruitless...
    You've obviously never worked on large applications with potentially large object graphs. Identity maps are crucial in ensuring the same object is never reconstituted more than once from the database. It's also necessary for bi-directional associations where you can break a cyclic dependency by using lazy loading. When the lazy loaded object is reconstituted, it can simply pull the associated object from the identity map.

  12. #12
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Obviously?

    I don't particularly favour the Identity Map in regards to PHP for the reason I gave earlier; It's got nothing to do with scale at all at the end of the day, when you consider that you have that Identity Map to maintain from one request to another.

    A cache would help, but only in so far, it's not a solution. What happens when your Identity Map has stale data, or begins to grow? When do you make the choice between the convienence and performance in that case?

    Don't talk to me about the benefits as I've been down that road myself; I've bought the -beep- t-shirt, mug and key ring. I can tell you from my own experience, it's just not worth the hassle of having an Identity Map with PHP and it's architecture, presently as it stands.

    I agree with the point of Lazy Initialisation, which does have it's uses but I have to question your design decisions.

  13. #13
    SitePoint Addict Jasper Bekkers's Avatar
    Join Date
    May 2007
    Location
    The Netherlands
    Posts
    282
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston View Post
    When do you make the choice between the convienence and performance in that case?
    Although the article is on O/R mappers and caching, an Identity map basically serves the same purpose. Frans Bouma explains just how reasonable it is to have an Identity map for performance reasons. (Spoiler: it's not).
    Design patterns: trying to do Smalltalk in Java.
    I blog too, you know.

  14. #14
    SitePoint Wizard REMIYA's Avatar
    Join Date
    May 2005
    Posts
    1,351
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here is the updated version. Changes from first:
    - dynamic table loading on runtime
    - initialization structure changed adding key to get records
    - no more double undescore (__) but (_)

    PHP Code:
    /**
     * <br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/">Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 License</a>.
     * @package MVCS
     * @copyright &copy 2007 Remiya
     */
    abstract class MVCS_DAO{
        private 
    $fields = array(); private $field_tables = array();
        private 
    $listeners = array();
        private 
    $tables = array();
        protected 
    $structure null;
        protected function 
    __construct(){
            echo 
    "Loading <b>".get_class($this)."</b> DAO...<br>";
            
    $this->_load_structure();
            foreach(
    $this->structure as $field=>$value){
                
    $this->fields[$field]=array();
                
    $this->fields[$field]['table']=$value['table'];
                
    $this->fields[$field]['type']=$value['type'];
                
    $this->fields[$field]['changed']=false;
                
    $this->fields[$field]['value']=null;
                
    // TABLES
                
    if(isset($this->tables[$value['table']])==false){
                    
    $this->tables[$value['table']]=array();
                    
    $this->tables[$value['table']]['loaded'] = false;
                    
    $this->tables[$value['table']]['fields'] = array();
                }
                if(isset(
    $this->tables[$value['table']]['by'])==false)$this->tables[$value['table']]['by']=$value['by'];
                
    $this->tables[$value['table']]['fields']['name'] = $field;
                
    $this->tables[$value['table']]['fields']['type'] = $value['type'];
           }
        }
        abstract public static function 
    getInstance();
        abstract protected function 
    _load_structure();
        final private function 
    __call($method$arguments){
           if(
    array_key_exists($method,$this->fields)===false)trigger_error('ERROR: Field <b>'.$method.'</b> not in '.get_class($this).' structure!',E_USER_ERROR);
           if(
    count($arguments)==0){
               return 
    $this->__get($method);
           }else{
               
    $this->__set($method,$arguments[0]);
               if(isset(
    $this->listeners['on_'.$method])){
                   
    $this->_update();
                   foreach(
    $this->listeners['on_'.$method] as $listener){
                       echo 
    "Updating listener <b>".$listener."</b><br>";
                       
    //$listener->update();
                   
    }
               }
           }
           
           return 
    $this;
        }
        final private function 
    __get($field){
            echo 
    "Getting <b>$field</b>...<br>";
            
    // Check if table loaded
            
    $table $this->fields[$field]['table'];
            if(
    $this->tables[$table]['loaded']==false){$this->_load_table($this->fields[$field]['table']);}
            return 
    $this->fields[$field]['value'];        
        }
        final private function 
    __set($field,$value){
            echo 
    "Seting <b>$field</b> to <b>$value</b>...<br>";
            
    // Check if table loaded
            
    $table $this->fields[$field]['table'];
            if(
    $this->tables[$table]['loaded']==false){$this->_load_table($this->fields[$field]['table']);}
            
    $this->fields[$field]['changed'] = true;
            
    $this->fields[$field]['value'] = $value;
        }
        final private function 
    _load_table($table_name){
            echo 
    "Loading table <b>$table_name</b> from database...<br>";
            
    $this->tables[$table_name]['loaded']=true;
        }
        final public function 
    _update(){
            
    $changed_fields = array();
            foreach(
    $this->fields as $field=>$properties){
                if(
    $properties['changed']==true){$changed_fields[] = $field;}
            }
            if(
    count($changed_fields)>0){
                echo 
    "Saving the fields <b>".implode("</b>, <b>",$changed_fields)."</b> of DAO in database...<br>";
                foreach(
    array_keys($this->fields) as $field){
                     
    $this->fields[$field]['changed']=false;
                }
            }else{
                echo 
    "No changes found...<br>";
            }
        }

        final public function 
    _add_listenter($event,$listener){
            echo 
    "Adding listener ".$listener." updated on ".$event."<br>";
            
    $this->listeners[$event][] = $listener;
        }
        final public function 
    __destruct(){
            echo 
    "In Destructor: Updating if changes found...<br>"
            
    $this->_update();
            echo 
    "Deleting <b>".get_class($this)."</b> DAO...<br>";
        }
    }
    class 
    User extends MVCS_DAO{
        private static 
    $_instance;
        protected function 
    __construct(){
            
    parent::__construct();
        }
        public static function 
    getInstance(){
            if (
    null === self::$_instance) {self::$_instance = new self();}
            return 
    self::$_instance;
        }
        protected function 
    _load_structure(){
            
    $this->structure = array(
                
    "username"=>array("type"=>"string""table"=>"users""by"=>"username"),
                
    "password"=>array("type"=>"string""table"=>"users""by"=>"username"),
                
    "firstname"=>array("type"=>"string","table"=>"users""by"=>"username"),
                
    "lastname"=>array("type"=>"string""table"=>"users""by"=>"username"),
                
    "email"   =>array("type"=>"string""table"=>"users""by"=>"username"),
                
    "photos"=>array( "type"=>"array",   "table"=>"photos","by"=>"username"),
                
    "albums"=>array("type"=>"array",   "table"=>"albums","by"=>"username")
            );
        }

    Example:
    PHP Code:
    // Creating new user
    $user User::getInstance();
    // Adding listeners
    $user->_add_listenter("on_firstname","FIRST NAME LISTENER 1");
    $user->_add_listenter("on_firstname","FIRST NAME LISTENER 2");
    // Changing username and forcing update
    // Table "users" is loaded on runtime
    $user->username("TOMMY")->_update();
    // Changing firstname and forcing update
    $user->firstname("Tom")->lastname("Curtis")->_update();
    echo 
    "User ".$user->username()." is ".$user->firstname()." ".$user->lastname()."<br />";
    // Table "photos" loaded on runtime
    echo "Getting user photos...<br />";
    $user->photos();
    // Changing email without forcing update
    $user->email("tommy@email.com");
    // The email get saved at object dying 
    Here is the example output
    Loading User DAO...
    Adding listener FIRST NAME LISTENER 1 updated on on_firstname
    Adding listener FIRST NAME LISTENER 2 updated on on_firstname
    Seting username to TOMMY...
    Loading table users from database...
    Saving the fields username of DAO in database...
    Seting firstname to Tom...
    Saving the fields firstname of DAO in database...
    Updating listener FIRST NAME LISTENER 1
    Updating listener FIRST NAME LISTENER 2
    Seting lastname to Curtis...
    Saving the fields lastname of DAO in database...
    Getting username...
    Getting firstname...
    Getting lastname...
    User TOMMY is Tom Curtis
    Getting user photos...
    Getting photos...
    Loading table photos from database...
    Seting email to tommy@email.com...
    In Destructor: Updating if changes found...
    Saving the fields email of DAO in database...
    Deleting User DAO...

  15. #15
    SitePoint Zealot
    Join Date
    Sep 2005
    Posts
    122
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston View Post
    ...when you consider that you have that Identity Map to maintain from one request to another.
    You don't need to persist the Identity Map over requests. There are still benefits to be had from scrapping it and rebuilding it per request. I already gave an example. Like I said, when you work on a large application where the same object could appear deep within two separate object graphs and then the same object is edited in both graphs, the benefits of the identity map become abundantly clear and absolutely necessary.

  16. #16
    PHP/Rails Developer Czaries's Avatar
    Join Date
    May 2004
    Location
    Central USA
    Posts
    806
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Remiya, I don't get why you have underscores in your functions at all. It seems much more natural to do a $user->update() or $user->save() without the underscore. If you are looking to avoid conflicts with column names as function calls, you may want to reconsider the way you get and set column names. The traditional DAO will use functions appended with "get" and "set" to avoid the confusion and conflicts with other class functions, like:
    PHP Code:
    $user->getUsername();
    $user->getLastname();
    $user->setUsername("bob");
    $user->save(); 
    Even still, the (more recently popular) ActiveRecord pattern will typically just use public class variables for this, like:
    PHP Code:
    $user->username;
    $user->lastname;
    $user->username "bob";
    $user->save(); 
    Also in your code, you are calling the _update() function 3 times, once after every field change. You may want to consider automatically tracking which fields have changed and then using ONE call to _update() at the end, when all the changes are made, like in the examples given above.

  17. #17
    SitePoint Wizard REMIYA's Avatar
    Join Date
    May 2005
    Posts
    1,351
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Czaries View Post
    Remiya, I don't get why you have underscores in your functions at all.
    You almost answered your question. I want to avoid conflicts with column names as function calls, and I want to give the user as much freedom as possible.
    Quote Originally Posted by Czaries View Post
    Even still, the (more recently popular) ActiveRecord pattern will typically just use public class variables for this.
    I personally don't like this approach. In addition to freedom of the user, I want to add extreme ease of use.
    Quote Originally Posted by Czaries View Post
    Also in your code, you are calling the _update() function 3 times, once after every field change. You may want to consider automatically tracking which fields have changed and then using ONE call to _update() at the end, when all the changes are made, like in the examples given above.
    The _update function is actually "FORCED UPDATE", and is added for the user to be able to update the database records, just before notifying the observers, because some of them may need also to make database calculations. (PS. The 3 calling of _update are just for demo purposes)

    In the most usual usage, you don't need to call the _update finction, nor _destruct, because the object is automaticly updated when dying with the end of the PHP script.
    Last edited by REMIYA; May 31, 2007 at 13:36.

  18. #18
    PHP/Rails Developer Czaries's Avatar
    Join Date
    May 2004
    Location
    Central USA
    Posts
    806
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by REMIYA View Post
    I personally don't like this approach. I addition to freedom of the user, I want to add extreme ease of use.
    The reason ActiveRecord patterns do this is because if you think about what your object represents, it makes perfect semantic sense to do it this way. Class variables are referred to as properties of that class. Since objects are made to represent actual things, your User object will represent an actual User of your system. That actual User will have certain properties as well, such as a username, a first name, a last name, etc., so it does make sense to get and assign the values this way, and is very easily readable.

    Functions, on the other hand, exist to break apart and isolate different pieces of logic. So semantically, it just doesn't make sense to use a function to retrieve or set data without a more clear naming convention. The code could become confusing to read the way it is setup now. When you called $user->photos() I actually looked back at the User class and was expecting to see a declared function called photos. How does one know what this function will do at a glance? I don't necessarily expect a function called photos() to return only the raw data in the database column. Being a function, I would expect it to do some sort of logic like getting the actual <img> tags for each photo or assembling the photos into an array for use in the template, etc.

    I also would not depend on the object getting destroyed as a way of saving - what happens if an error is encountered and you need to discard the changes? There is no current function to do that, and you can't destroy the object because that will automatically save and update the record. You're better off requiring an explicit function call after all your changes to $user->update() to save the record, both for error handling and readability (How does a programmer know the changes are automatically saved without reading all your class code?).

  19. #19
    SitePoint Wizard REMIYA's Avatar
    Join Date
    May 2005
    Posts
    1,351
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Czaries View Post
    Functions, on the other hand, exist to break apart and isolate different pieces of logic. So semantically, it just doesn't make sense to use a function to retrieve or set data without a more clear naming convention.
    Functions isolate different pieces of logic. Absolutely. Someone asked about validation. This is exactly where this comes in.

    At the set method the validation is to take part automaticly (NOT SHOWN HERE FOR THE BASIC CONCEPT IS SHOWN). So it will check if Username is of type String, if Email is valid email, etc. If error occurs it is trigerred before any database record is saved.

    About the naming convention, it is perfectly clear and concise. And the readability it is much, much easier. Look at this:

    PHP Code:
    $user1->reads("books")->how_often("2 per week")->pays_with("cash");
    $user2->reads("magazines")->how_often("1 per month")->pays_with("Visa"); 
    and there is no need to call save(), update(), etc.

    against:

    PHP Code:
    $user1->reads "books"
    $user1->how_often "2 per week";
    $user1->pays_with "cash"
    // If you don't call this your object will never get saved LOL
    $user1->save(); 

  20. #20
    PHP/Rails Developer Czaries's Avatar
    Join Date
    May 2004
    Location
    Central USA
    Posts
    806
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Everyone has different tastes on what looks and reads better. I personally prefer things on their own line. You obviously have different preferences.

    The example you used is quite the academic example. Let's try using code we might actually see, like with your User class.

    PHP Code:
    $user->username("test")->firstname("john")->lastname("doe"); 
    What is this doing? Searching for a record with all these properties? Updating it? We don't know because the code does not make it natually clear simply from reading it.

    PHP Code:
    $user->username "test";
    $user->firstname "john";
    $user->lastname "doe";
    $user->save(); 
    It is clear exactly what this is doing simply by reading only these lines, which do the same thing as the above.

    You mock the use of the required $user->save(); statement, but you don't realize that it's there to add clarity and concreteness to the code. Your lack of any such statement in the example you gave adds to the confusion. And as I said in my previous post, what if you encounter an error? You have not provided a way to discard the changes, and if you destroy the object it will automatically save. The save is passive, but it needs to be explicit.


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
  •