This document represent a proposal for __get __set "improvements", feels free to comment it, reject it or why not approve it.
Keywords and function names are just for understanding they should be rethinked if the design is accepted. I took care of Stanislav point of view and tried to merge his conception of the accessor system with mine. What i'm trying to do in this design : - do not remove overloaded variables declaration from class definition - make overloaded variables obvious to class reader - keep the 'undefined' feature into the model. So __get __set __call will be called if the attribute or method is not defined - limit PHP code length required by accessor usage and make overload easier to maintain (no private hashtable required but still possible to use) - ensure that __set and __get will be called for overloaded variables even if variable value is set (unless overload is removed for this variable) - prevent recursion - selective choice of overloaded attributes with no loss of performance - stay as near as possible from current ZendEngine2 C code. * the model requires introduction of a new attribute keyword here symbolized by 'overloaded'. Overloading an attribute means binding get and set calls for this attribute to __get and __set class method. class Foo { /** * Access to $bar is done with __get and __set * * In this example, __set is not defined, any * call like "$foo->bar = 'value';" will produce * a direct access to the variable. */ overloaded $bar; /** * Regular variable */ var $biz; /** * __get accessor. * * This accessor is called whenever an overloaded * object variable has to be retrieved. * * At this time, it will also be invoqued for * undefined variables. */ function __get($varname) { if ($varname == "bar") { // ... code return bar value or anything else } // ... } }; $f = new Foo; echo $f->bar; // calls __get echo $f->biz; // no call to __get // same for __set if __set defined * concerning recusion problem two point of view, please comment : - disabling recursion in accessors : in __XXX() access to an overloaded variable is direct. ++ recursion errors limitation ++ no zend_object_handlers.c modification -- the coder has to know which attributes requires overloading to call __set and __get when appropriate (limit dynamic generation of overloaded attributes (see below)) class Foo { overloaded $bar; var $biz; function __set($var, $value) { // ... $this->__get($bar); // force call of getter // ... echo $this->bar; // direct access // ... $this->$var = $value; // direct access } function __get($var) { // ... $this->bar; // no error direct access } } - give functions to bypass accessors ++ no need to worry about which attributes requires __get and __set as ours getter and setter will be called when appropriate. -- the coder has to use the direct access function to break recursion class Foo { overloaded $bar; var $biz; function __set($var, $value) { // ... $this->bar; // call __get // ... $this->biz; // direct access // set value with direct access object_set($this, $var, $value); // ... } function __get($var) { // ... $this->bar; // BEWARE recursive call // ... object_get($this, "bar"); // direct access } }; * declaring an overloaded attribute whithout __get or __set has no consequence, the attribute is treated as a regular public attribute. (may issue a warning in the future) class Foo { // ? should ? issue a warning as no __get / __set // is defined in the class overloaded $foo; }; * a way to define dynamically an 'overloaded' variable into the object here i named it 'overload_var' but the name is just for understanding. class Foo { function __set($varname, $value) { // if the object doesn't know this attribute // we create a new overloaded attribute if (!isset($this->$varname)) { // futher modification of this variable will // invoque the __set method overload_var($this, $varname); } $this->$varname = $value; } }; $foo->unknownVarName = "value"; // call __set $foo->unknownVarName = "other"; // still call __set // remove overload on specified attribute, the oposite of // overload_var() unoverload_var($foo, "unknownVarName"); Note that the 'overload_var' is optional, when not used, the attribute is set like any other public attribute. The function overload_var may also dynamically transform a regular variable into an overloaded one (please comment). * a way to prevent calls of accessors on *undefined* variables and methods should be provided in the future so the class maintainer would decide if its class will handle them or not. class Foo { function __get($varname) { // ... } }; // do not accept undefined attributes (reactivate error // reporting for this object) disable_undefined_overload('Foo'); * Changes from current design : - new property keyword ('overloaded') - a way to keep track of overloaded properties may be a new hashtable in zend_class_entry just like default, private or protected ones. (note: zend.h contains a structure named "zend_overloaded_element" it seems that no source use it) - __get / __set called if - exists __get / __set (nothing to modify) - the property does not exists (nothing to modify) - the property is declared overloaded (modification required) - other changes depends of - recursion choices - new functions - disabling undefined properties - warning issue * Things to think about : - inheritance and __set / __get overwrite may requires parent::__set() call leaved to php developper. - overloaded methods and __call Let me know what you think about this design. Laurent -- PHP Development Mailing List <http://www.php.net/> To unsubscribe, visit: http://www.php.net/unsub.php