SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 35
  1. #1
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    930
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)

    Can I intercept setting of any public property $obj->var = 'value'?

    I would like to accomplish the following - whenever a public property of an object is set, preferably only outside the class, I want a given function to be called that could for example change the value before assignment or log the fact of assigning somewhere else:
    Code:
    $obj = new MyClass;
    $obj->var = 'value';
    At this point I would like some other method to be called behind the scenes that will be passed the name and the new value of the property being set. It would even be ok, if
    Code:
    $obj->var = 'value';
    would secretly invoke
    Code:
    $obj->var('value');
    I know there is a magic method __set() but it seems to work only on non-existent properties while I want this to work when setting any property. Is this possible? I've heard of some magic possible with SPL or Reflection but couldn't find anything specific for this.

  2. #2
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,192
    Mentioned
    17 Post(s)
    Tagged
    4 Thread(s)
    Set the property indirectly. Properties should only be directly accessible within the class anyway.

    PHP Code:
    class Foo {

        protected 
    $var;

        public function 
    setVar($var) {
        
            
    $this->var $this->_handleVar($var);
        
        }
        
        protected function 
    _handleVar($var) {
        
            
    // log or change value before assignment

            
    return $var.' changed';
        
        }


    is there any particular reason why the above can't be done?

  3. #3
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,192
    Mentioned
    17 Post(s)
    Tagged
    4 Thread(s)
    You could do something similar with magical methods, but I really think it would be over complicating things.

    PHP Code:
    class Image {

        protected 
    $width;
        protected 
    $height;

        public function 
    __set($name,$value) {
        
            switch(
    $name) {
                case 
    'width':
                    
    $this->width $this->_handleWidth($value);
                    break;
                    
                case 
    'height':
                    
    $this->height $this->_handleHeight($value);
                    break;
            }
        
        }
        
        protected function 
    _handleWidth($width) {
        
            
    // log or change value before assignment
            
    return ($width-100);
        
        }
        
        protected function 
    _handleHeight($height) {
        
            
    // log or change value before assignment
            
    return ($height+100);
        
        }


    Using property and method exists with some string manipulation the process could be made smarter. Where if the property exists it checks for the transform method and calls it if it exists.

  4. #4
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    930
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Thanks, that is an idea I have come across but the point is I want to leave the properties public. I am looking for a solution similar to SPL ArrayAccess which can map $obj['a'] = 5; to $obj->a = 5;

    Only in this case I want $obj->a = 5; to be mapped to $obj->a(5);

  5. #5
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Wouldn't this approach be a little obscure? I'm not saying it isn't possible, but IMHO, if you need to add logic when setting a property, you should use a setter.

    There's a lot to be said for API clarity, why would you need to provide this pseudo magical function when a simple setter would suffice? Is there a specific need you're trying to address, to me, it sounds like you're approaching a problem from the wrong angle.

    Given my propensity for forgetfulness ,I'm pretty sure I'd be scratching my head 2 years down the line (when using a class that had this magic feature) wondering why the value I set, isn't the value being set.

    My 2c.
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  6. #6
    SitePoint Wizard silver trophybronze trophy Stormrider's Avatar
    Join Date
    Sep 2006
    Location
    Nottingham, UK
    Posts
    3,133
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    __set should work fine for this in any case surely?

  7. #7
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Stormrider View Post
    __set should work fine for this in any case surely?
    Sure, you can use __set and __get but, to me, this sounds like the OP has a more specific issue which we could address, just throwing some exploratory questions out there.

    You could use the following, but should you, that's my point of view here.
    PHP Code:
    <?php
    class Foo
    {
        private 
    $bar;
        
        public function 
    __set($key$value)
        {
            if(
    property_exists($this$key))
            {
                
    $this->$key = (Integer)$value 10;
            }
        }
        
        public function 
    __get($key)
        {
            if(
    property_exists($this$key))
            {
                return 
    $this->$key;
            }
        }
    }

    $oFoo = new Foo();
    $oFoo->bar 1;
    echo 
    $oFoo->bar#11
    ?>
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  8. #8
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    930
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by SilverBulletUK View Post
    Wouldn't this approach be a little obscure? I'm not saying it isn't possible, but IMHO, if you need to add logic when setting a property, you should use a setter.

    There's a lot to be said for API clarity, why would you need to provide this pseudo magical function when a simple setter would suffice? Is there a specific need you're trying to address, to me, it sounds like you're approaching a problem from the wrong angle
    Yes, you are absolutely right, what I'm trying to accomplish is against the rules of clean API in favour of gaining more speed (I know, speed is not the right goal for a good OOP programmer ).

    So let me explain: I have created a very simple active record system that is designed to be fast while providing the basic conveniences I find most important. Something like Propel light with only the functions I need. One of the 'features' is that all properties corresponding to a db row are public and no getters or setters are required (although they are available if I needed them for some reason):
    Code:
    $user = UserPeer::getByPK(777);
    $username = $user->username;
    
    $user->is_online = 1;
    $user->save();
    But now the save() method doesn't know which properties have changed so it sends all fields back to the db in an UPDATE sql. So I would like to track which fields have changed and for this I need setters. This provides inconsistency in my approach because for getting properties I would access them directly while for setting I would have to use setters. Doing the magic I wrote in my original post I could retain consistency in that.

    Of course, as you probably suspect I don't want to give up direct access to properties, I want them to be fast and don't want to apply any magic for this. But saving to db is usually not so frequent on a live site so I don't mind using a setter for that. I hope it's clear now.

  9. #9
    SitePoint Wizard silver trophybronze trophy Stormrider's Avatar
    Join Date
    Sep 2006
    Location
    Nottingham, UK
    Posts
    3,133
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Regardless of what is best or not, something like this should be what you need:

    PHP Code:
    class Whatever {
     private 
    changedFields = array();

     public function 
    __set ($key$value) {
      
    $this->changedFields[] = $key;
      
    $this->$key $value;
     }


  10. #10
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    930
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Thanks, but I don't this this would work because __set() is invoked only on inaccessible properties while in my case all the properties are public. So
    Code:
    $obj->a = 'value';
    will not call
    Code:
    $obj->__set();
    because
    Code:
    public $a;
    Last edited by Lemon Juice; May 8, 2009 at 05:37. Reason: mistake in first line of code

  11. #11
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    But essentially it is public, just by-proxy.
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  12. #12
    SitePoint Wizard silver trophybronze trophy Stormrider's Avatar
    Join Date
    Sep 2006
    Location
    Nottingham, UK
    Posts
    3,133
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Lemon Juice View Post
    Thanks, but I don't this this would work because __set() is invoked only on inaccessible properties while in my case all the properties are public. So
    Code:
    $obj->a();
    will not call
    Code:
    $obj->__set();
    because
    Code:
    public $a;
    Well it wouldn't anyway, because $obj->a() would be looking for a function, not a property

    You could store all properties in a private array instead then:

    PHP Code:
    class Whatever {
     private 
    changedFields = array();
     private 
    data = array();

     public function 
    __set ($key$value) {
      
    $this->changedFields[] = $key;
      
    $this->data[$key] = $value;
     }

     public function 
    __get ($key) {
      if (isset(
    $this->data[$key])) {
       return 
    $this->data[$key];
      } else {
       
    //trigger error? Return false or null? up to you
      
    }//if
     
    }

    Anything using the class would be none the wiser.

  13. #13
    SitePoint Wizard silver trophybronze trophy Stormrider's Avatar
    Join Date
    Sep 2006
    Location
    Nottingham, UK
    Posts
    3,133
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    And to be honest, I don't think this is that bad a use of __set and __get - the data isn't being modified, it's just being used to help set a flag elsewhere so that updates are more efficient. I see nothing wrong with that.

    I would say though that storing the data twice and comparing them to decide what has changed would be better - With the above system, I could 'change' the data back to what it was in the first place, and it would be flagged as a change, when the data is in fact the same.

  14. #14
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    930
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Sorry, my mistake, of course I meant was that
    Code:
    $obj->a = 'value';
    will not invoke __set() because $a is public.

    Quote Originally Posted by Stormrider View Post
    And to be honest, I don't think this is that bad a use of __set and __get - the data isn't being modified, it's just being used to help set a flag elsewhere so that updates are more efficient. I see nothing wrong with that.
    I agree this use of __set is quite nice, however I doubt it will give any efficiency increase - on the one hand updates will not send redundant data but on the other magic __set and __get are so slow in php that overall the performance could be worse than sending all unnecessary values back to the db. Perhaps this could help only in case of large text or blob fields. Standard setters will be much faster.

    Anyway, I will never use __get for accessing properties in active record because this would be quite a serious slow down. __get is about 5 times slower than a standard getter and accessing properties is used very often.

    I would say though that storing the data twice and comparing them to decide what has changed would be better - With the above system, I could 'change' the data back to what it was in the first place, and it would be flagged as a change, when the data is in fact the same.
    Maybe, but I think cases where data is changed back to the same are marginal while this would make every SELECT query less efficient because each new object (or array) would need to be cloned.

  15. #15
    SitePoint Wizard silver trophybronze trophy Stormrider's Avatar
    Join Date
    Sep 2006
    Location
    Nottingham, UK
    Posts
    3,133
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    I wouldn't worry about efficiency - sending smaller queries to the database server is always a good idea, as it is often the database that is the bottleneck. If you are coding for efficiency (as in, php execution), you are probably doing it wrong. __set and __get aren't slow enough for it to be a concern, not by a long way. Imagine if you come across a database table with large amounts of data in each field - then it will definitely become a problem sending redundant data.

    Only in extreme cases should you need to code for efficiency - this kind of stuff isn't a problem.

    It wouldn't be the SELECT query that is less efficient - you just run the query once and then copy the data. It really isn't a problem, speed wise.

  16. #16
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,192
    Mentioned
    17 Post(s)
    Tagged
    4 Thread(s)
    My active record merely stores every change in a multidimensional array.

    PHP Code:
    array(
         
    'name'=>array('current name','previous name')

    The first item inside the nested array is the dynamic property. There are also methods to extract values at specific indexes if needed.

    The active record also has a hasChanged() method. It merely checks if a dynamic property exists and has changed.

    PHP Code:
    if($user->hasChanged('pwd')===true) {

    The magical methods are a convenience though and just reroute to the appropriate interface methods.

    PHP Code:
    $user->getProperty('title'

  17. #17
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,192
    Mentioned
    17 Post(s)
    Tagged
    4 Thread(s)
    If you would like you play around with the below class and interface and learn from it. This is the data container for my active record.

    PHP Code:
    interface IActiveRecordDataEntity {

        public function 
    getProperty($pName);
        public function 
    setProperty($pName,$pValue);
        public function 
    hasProperty($pName);
        public function 
    hasChanged($pName);
        public function 
    addRecord($pPropertyName,IActiveRecordDataEntity $pRecord,$pArrayByDefault=false);
        public function 
    getRecord($pPropertyName,$pPrimaryKey,$pField);
        public function 
    removeProperty($pPropertyName);
        public function 
    getData();
        public function 
    cast();


    PHP Code:
    class ActiveRecordDataEntity implements IActiveRecordDataEntity {

        private 
    $_data;
        
        public function 
    __construct() {
        
            
    $this->_data = array();
        
        }

        public function 
    setProperty($pName,$pValue) {
        
            if(
    $this->hasProperty($pName)===true) {
            
                
    array_unshift($this->_data[$pName],$pValue);
                
            } else {
            
                
    $this->_data[$pName] = array($pValue);
                
            }
        
        }
        
        public function 
    getProperty($pName) {
        
            if(
    $this->hasProperty($pName)===true) {
            
            
                return 
    $this->_data[$pName][0];
            
            }
        
        }
        
        public function 
    hasProperty($pName) {
        
            return 
    array_key_exists($pName,$this->_data);
        
        }
        
        public function 
    getRecord($pPropertyName,$pPrimaryKey,$pField) {
        
            if(!
    array_key_exists($pPropertyName,$this->_data)) return false;
            
            if(!(
    $this->_data[$pPropertyName][0] instanceof ActiveRecord) && $this->_data[$pPropertyName][0] instanceof arrayaccess) {
            
                foreach(
    $this->_data[$pPropertyName][0] as $record) {
                
                    if(
    $record->$pField == $pPrimaryKey) return $record;
                
                }
            
            } else {
                
                if(
    $this->_data[$pPropertyName][0]->$pField == $pPrimaryKey) {
                    
                    return 
    $this->_data[$pPropertyName][0];
                
                }
                
            }
            
            return 
    false;
        
        }
        
        public function 
    addRecord($pPropertyName,IActiveRecordDataEntity $pRecord,$pArrayByDefault=false) {
        
            if(
    array_key_exists($pPropertyName,$this->_data)===true) {
            
                if(
    $this->_data[$pPropertyName][0] instanceof arrayaccess) {
                
                    
    $this->_data[$pPropertyName][0][] = $pRecord;
                
                } else {    
                
                    
    //$this->_data[$pPropertyName][0] = array($this->_data[$pPropertyName][0]);
                    
    $this->_data[$pPropertyName][0] = new ActiveRecordCollection($this->_data[$pPropertyName][0]);
                
                }
            
            } else {
                
                
    // for a hasMany relationship with only one item. Otehrwise if something
                // only has one item in its result set but has a hasMany relationship
                // a array would not exists which seems wrong.
                
    if($pArrayByDefault === true) {
                    
    $this->_data[$pPropertyName] = array(new ActiveRecordCollection($pRecord));
                } else {
                    
    $this->_data[$pPropertyName] = array($pRecord);
                }
            
            }
        
        }
        
        public function 
    removeProperty($pPropertyName) {
        
            if(
    $this->hasProperty($pPropertyName)===true) {
                
                unset(
    $this->_data[$pPropertyName]);
                return 
    true;
                
            } else {
            
                return 
    false;
                
            }
        
        }
        
        public function 
    getData() {
        
            return 
    $this;
        
        }
        
        public function 
    hasChanged($pName) {
        
            if(
    $this->hasProperty($pName)===true) {
            
                return 
    count($this->_data[$pName])>1?true:false;
            
            }
        
        
        }
        
        public function 
    cast() {
        
        
            foreach(
    $this->_data as $key=>$data) {
                
                
    $value $this->_data[$key][0];
                
    $this->_data[$key] = array($value);
            
            }
        
        
        }
        
        
        
        
        


    practical usage
    PHP Code:
    $data = new ActiveRecordDataEntity();
    $data->setProperty('name','oddz');
    echo 
    $data->getProperty('name');  // 'oddz' 
    There isn't a practical advantage of hard coding the properties into the class if your creating a generic system.

  18. #18
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,192
    Mentioned
    17 Post(s)
    Tagged
    4 Thread(s)
    In a nutshell then ActiveRecord also implements that interface so any instance of IActiveRecordDataEntity can be used interchangably.

    PHP Code:
    abstract class ActiveRecord implements IActiveRecordDataEntity {

        private 
    $_data;
        
        public function 
    __construct() {
        
            
    $this->_data = new ActiveRecordDataEntity();
        
        }

        public function 
    __set($pName,$pValue) {
        
            
    $this->setProperty($pName,$pValue);
        
        }
        
        public function 
    __get($pName) {
        
            return 
    $this->getProperty($pName);
        
        }
        
        public function 
    setProperty($pName,$pValue) {
        
            
    $this->_data->setProperty($pName,$pValue);
        
        }
        
        public function 
    getProperty($pName) {
        
            if(
    $this->_data->hasProperty($pName)===true) {
            
                return 
    $this->_data->getProperty($pName);
            
            } else {
            
                
    $config ActiveRecordModelConfig::getModelConfig(get_class($this));
                
                foreach(
    $config->getHasMany() as $model) {
                    if(
    strcmp($pName,$model)==0) {
                        
    $this->setProperty($pName,new ActiveRecordCollection());
                        return 
    $this->_data->getProperty($pName);
                    }
                }
            
            }
        
        }
        
        public function 
    hasProperty($pName) {
        
            return 
    $this->_data->hasProperty($pName);
        
        }
        
        public function 
    removeProperty($pName) {
        
            return 
    $this->_data->removeProperty($pName);
        
        }
        
        public function 
    getRecord($pPropertyName,$pPrimaryKey,$pField) {
        
            return 
    $this->_data->getRecord($pPropertyName,$pPrimaryKey,$pField);
        
        }
        
        public function 
    addRecord($pPropertyName,IActiveRecordDataEntity $pRecord,$pArrayByDefault=false) {
        
            
    $this->_data->addRecord($pPropertyName,$pRecord,$pArrayByDefault);
        
        }
        
        public function 
    getData() {
        
            return 
    $this->_data;
        
        }
        
        public function 
    cast() {
        
            
    $this->_data->cast();
        
        }
        
        public function 
    hasChanged($pName) {
        
            return 
    $this->_data->hasChanged($pName);
        
        }
    }
    ?> 
    As you should see the magical set and get methods merely redirect to the appropriate interface method. So they can either be used or the actually interface getter and setter can used directly. Either way they do the same thing.

  19. #19
    . shoooo... silver trophy logic_earth's Avatar
    Join Date
    Oct 2005
    Location
    CA
    Posts
    9,013
    Mentioned
    8 Post(s)
    Tagged
    0 Thread(s)
    @Lemon Juice, Stop worrying about performance. using methods over direct public properties is not going to make a dent in performance. If you are so concerned about performance, then STOP doing MIRCO-OPTIMIZATIONS! Profile your code and find the real slow parts. 1 or 2 ms difference is not something to be concerned about.

    Read: Common Optimization Mistakes Slides

    You have to realize using public properties goes against the problem you are trying to solve! Just use accessor methods, seriously there is no reason not too.
    Logic without the fatal effects.
    All code snippets are licensed under WTFPL.


  20. #20
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    930
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Stormrider View Post
    I would say though that storing the data twice and comparing them to decide what has changed would be better - With the above system, I could 'change' the data back to what it was in the first place, and it would be flagged as a change, when the data is in fact the same.
    I checked that and indeed performance-wise this system is not bad at all. I compared the time it takes to clone an object holding a quite large database record to sending an UPDATE query with the same data - cloning object was extremely fast while the UPDATE quite slow and becoming proportionately slower as the query grew in size. Even comparing the old data to new was much faster than sending large updates. So finally I implemented the system you describe with comparing old to new data and it seems to work quite well. However, I didn't switch to getters and setters

    Quote Originally Posted by logic_earth View Post
    @Lemon Juice, Stop worrying about performance. using methods over direct public properties is not going to make a dent in performance. If you are so concerned about performance, then STOP doing MIRCO-OPTIMIZATIONS! Profile your code and find the real slow parts. 1 or 2 ms difference is not something to be concerned about.

    Read: Common Optimization Mistakes Slides

    You have to realize using public properties goes against the problem you are trying to solve! Just use accessor methods, seriously there is no reason not too.
    Interesting read, thanks. It's not that I don't agree with these ideas, I just don't think I really need getters and setters for active record so much. I have coded a few sites using both Propel and my own system with public properties and I find the need for getters and setters very rare - if I don't find much use for them then I can choose the method that will execute faster.

    With Propel I could feel that the performance was a bit sluggish when I needed to do lots of db access - generally the server managed OK but I had to think about optimizing code in a few places just because of the heavy ORM layer. And I didn't really find the need to abstract every database field with a getter and setter. However, I still use getters and setters in the active row objects in situations where I need to manipulate the data in some way, for example $obj->getPageLink() while there is no 'link' field in the table and the link is created from other fields like an ID or name - I find this very useful. I know you might say that I may not know if I wanted to manipulate data sometime in the future and having a getter would make the implementation of such a manipulation easy once the application is made but those cases are very rare when I need to make this kind of switch.

    I don't strive to abstract from db like a full-featured ORM tries to do, I just want an easy and flexible way of accessing db and having objects with data that I can extend with methods is very convenient for me. So I have kept what I wanted while having a system that executes fast and I can get most data from db with almost no overhead, only marginally slower than pure mysql(i) functions. Maybe I think too much about optimization now but later when I start coding I don't have to worry about it as much as with slower implementations.

  21. #21
    . shoooo... silver trophy logic_earth's Avatar
    Join Date
    Oct 2005
    Location
    CA
    Posts
    9,013
    Mentioned
    8 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Lemon Juice View Post
    ...I just don't think I really need getters and setters for active record so much. I have coded a few sites using both Propel and my own system with public properties and I find the need for getters and setters very rare - if I don't find much use for them then I can choose the method that will execute faster...
    The current problem you are trying to solve, you cannot use public properties. It is really simple tho:

    PHP Code:
    class Testing {
        protected 
    $propa$propb$propc;

        public function 
    __set $prop$value )
        {
            if ( 
    property_exists$this$prop ) )
                
    $this->{ $prop } = $value;
            return 
    $this;
        }
        
        public function 
    __get $prop )
        {
            if ( 
    property_exists$this$prop ) )
                return 
    $this->{ $prop };
        }

    You keep the same interface as $this->some_public_propertie = 'whatever'
    Logic without the fatal effects.
    All code snippets are licensed under WTFPL.


  22. #22
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    930
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by logic_earth View Post
    The current problem you are trying to solve, you cannot use public properties. It is really simple tho:

    PHP Code:
    class Testing {
        protected 
    $propa$propb$propc;

        public function 
    __set $prop$value )
        {
            if ( 
    property_exists$this$prop ) )
                
    $this->{ $prop } = $value;
            return 
    $this;
        }
        
        public function 
    __get $prop )
        {
            if ( 
    property_exists$this$prop ) )
                return 
    $this->{ $prop };
        }

    You keep the same interface as $this->some_public_propertie = 'whatever'
    Can you explain what problem you are referring to? My main problem was to optimize db updates when doing save() in an efficient way and I have already done this with Stormrider's idea, although I initially thought I would find a different solution. So what problem were you trying to solve with the above code?

  23. #23
    . shoooo... silver trophy logic_earth's Avatar
    Join Date
    Oct 2005
    Location
    CA
    Posts
    9,013
    Mentioned
    8 Post(s)
    Tagged
    0 Thread(s)
    This one posed at that very top of this topic.
    ...whenever a public property of an object is set...I want a given function to be called...
    Logic without the fatal effects.
    All code snippets are licensed under WTFPL.


  24. #24
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    930
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by logic_earth View Post
    This one posed at that very top of this topic.
    Ok, I see. I was asking because SilverBulletUK posted something very similar so I thought you had something different in mind. The reason why I wrote "whenever a public property of an object is set" was that I wanted them (properties) to really stay public so that accessing them was as fast as possible - applying magic methods like this would slow down property access. I could use this solution with _get and _set in the future if I needed to but for now there is no need because I achieved my primary goal - optimizing updates on save() - by comparing old data to new.

  25. #25
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,192
    Mentioned
    17 Post(s)
    Tagged
    4 Thread(s)
    Hard coding the properties into the model as public members doesn't make for a very flexible system. Especially if you start to consider the need to overload a single ActiveRecord with other ActiveRecords or overload calculated columns. For instance, to create a aggregate calculation when finding data. A fundamental advantage of the active record is the flexibility of dynamic properties. The time it takes to run array_key_exists() on a array isn't worth removing the dynamic nature of the pattern. If you don't like __get and __set then use a method: $record->getProperty('title') | $record->setProperty('title','gh jkdh'). Either way by removing the dynamic nature your defeating the purpose of the pattern.

    $category = new Category(20);
    $category->products[] = new Product(array('name'=>'product'));
    $category->save();
    Last edited by oddz; May 12, 2009 at 11:33.


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
  •