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