The way ActionScript 2.0 solves this is with set and get keywords on
function declarations. Any class can contain as many setter/getters as
they need,. Since we dont want to introduce any new keywords how about
something similar with __set and __get?
<?php
class Foo
{
private $_fooProp;
function __set fooProp($val)
{
$this->_fooProp = $val; // $_fooProp is read only
}
function __set barProp($val)
{
// logic to set barProp...
}
function __get barProp($val)
{
// logic to get barProp...
}
}
?>
To allow for BC, if there is no identifier after the __set/__get then
the existing rules apply.
-Justin
Derick Rethans wrote:
Hello!
we're finding some problems with property overloading (__get() and
__set()). Here is an RFC describing what we'd like to see changed.
Please comment on this.
Introduction:
PHP currently supports property overloading with the magic functions __get()
and __set(). Those methods are called when the code "echo $object->a" or
"$object->a = 42" are executed and the property "a" is not declared in the
class. The magic methods are responsibly for:
- checking if the property actually "exists"
- setting the value or returning the value depending on the action
Problems:
1. There is no way to document the 'virtual' properties with any of the existing
documentation tools (such as phpdoc and doxygen)
2. There is no way how the magic methods know if a specific 'virtual' property
exists or not as those properties are not declared usually - unless you
define an array with property names as a class constant (which is not
allowed either).
3. There is no way for the magic methods to return a meaningfull error when a
property doesn't "exist". Of course it is possible to throw an error with
"trigger_error" or "throw" in case a property doesn't "exist" in a specific
class, but the file and line numbers would not match the actually get/set
action. debug_backtrace() can be used to retrieve the correct file and line,
but as you have to do this for every class where you want to use setters and
getters *and* you have to implement your own error message rendering
function this is not really a suitable option either.
Solutions:
- For problem 1. we can introduce a keyword (or use an existing one) to define
that it is a virtual property ('abstract' or 'virtual' come to mind). When
declaring it like this it's easy to document, and we can also implement
visibility for those virtual properties. Marcus already has a patch for
this somewhere, which uses the "abstract" keyword for this purpose:
<?php
class Base
{
/**
* @var int Contains all X
*/
abstract public $x = 1;
/**
* @var int Contains all Y
*/
abstract protected $y = 2;
// abstract private $z = 3; abstract properties cannot be private
}
?>
- In combination to the introduced keyword we need an easy way to check if a
passed property name is declared in the class as 'virtual'. Currently (with
the 'abstract' keyword properly implemented) you'd have to do:
<?php
class Base
{
abstract public $x = 1;
function __get($name)
{
try {
$prop = new ReflectionProperty('Base', $name);
if ( !$prop->isAbstract() ) {
/* throw error */
}
} catch ($e) {
/* throw error */
}
}
}
$b = new Base();
echo $b->foo;
?>
This is ofcourse overly complicated. A better workable solution would be -
without breaking BC (suggestions for syntax here are very welcome):
<?php
class Base
{
abstract public $x = 1;
function __get($name)
{
if (!self::isVirtual($name))) {
/* throw error */
}
}
}
$b = new Base();
echo $b->foo;
?>
- Problem 3 can be solved by:
* allowing optional by-ref parameters to the __set
and __get function, so that their signatures become:
function __set($name, $value [, &$error] )
function __get($name [, &$error] )
If the parameter is not given things behave just like they do now ->
__set
and __get can not throw meaningful errors with the correct file/line of
the
conflicting statement
If the parameter is used in the function's declaration and is set to
"false" when the __set or __get function returns, the engine can throw
an
error on the assignment line with the correct file/line combination. If
it's set to "true" (or "null") then the engine should not throw any
error.
* Use a different __set and __get function for 'abstract' properties, then
the engine can already determine if you're doing something wrong before
executing the __set and __get methods.
regards,
Derick
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php